Доступ к HTTP-заголовкам веб-страницы в JavaScript

Как получить доступ к заголовкам HTTP-ответов страницы через JavaScript?

Связано с этим вопросом , который был изменен, чтобы запрашивать доступ к двум конкретным заголовкам HTTP.

По теме:
Как получить доступ к полям заголовка HTTP-запроса через JavaScript?


person keparo    schedule 20.10.2008    source источник
comment
@ user2284570 - Нет. этот вопрос касается заголовков ответа, а не заголовков запроса.   -  person Quentin    schedule 05.12.2018
comment
Хотя вы не можете подготовить какие-либо заголовки ответа HTML в JS, вы можете читать заголовок Server-Timing и передавать через него произвольные данные типа "ключ-значение". См. мой ответ.   -  person jakub.g    schedule 15.02.2021


Ответы (18)


Невозможно прочитать текущие заголовки. Вы можете сделать еще один запрос к тому же URL-адресу и прочитать его заголовки, но нет гарантии, что заголовки в точности равны текущему.


Используйте следующий код JavaScript, чтобы получить все заголовки HTTP, выполнив get запрос:

var req = new XMLHttpRequest();
req.open('GET', document.location, false);
req.send(null);
var headers = req.getAllResponseHeaders().toLowerCase();
alert(headers);
person Raja    schedule 03.02.2011
comment
Саид, может быть, не лучший вариант для автора вопроса ... Я думаю, это потому, что он не обращается к заголовкам загруженного ресурса, а делает новый запрос ... очевидно, он знает лучше всех, какой лучший ответ, и сделал его сам - person mykhal; 28.07.2011
comment
Я бы подумал о том, чтобы пометить это, чтобы модератор мог правильно отметить. Отвечает на проблему, как указано. - person thesmart; 28.12.2011
comment
В зависимости от того, какой заголовок вы идете после, вы можете использовать глагол «HEAD». - person scottrudy; 02.03.2012
comment
Я считаю, что заголовки файлов cookie опущены. - person Olivier Lalonde; 26.04.2013
comment
можете ли вы изменить заголовок ответа, чтобы браузер действовал определенным образом - person Muhammad Umer; 10.07.2013
comment
Создание нового запроса будет работать только в том случае, если требуемые значения ответа будут идентичны от одного запроса к другому. Это будет зависеть от вашего приложения, поэтому ваш опыт при таком подходе будет отличаться. - person keparo; 17.08.2013
comment
Этот взлом может сработать в некоторых сценариях, но он не будет работать вообще, если страница, содержащая сценарий, была сгенерирована в ответ на запрос POST, и не поможет, если вы пытаетесь определить, обнаружил ли сервер ошибку. (HTTP 5XX) при обработке исходного запроса. - person claymation; 23.10.2014
comment
Также есть GetResponseHeader('headerName'), если вас интересует только значение одного заголовка, что, на мой взгляд, является наиболее распространенным вариантом использования. - person BlueRaja - Danny Pflughoeft; 14.01.2015
comment
Этот ответ ужасно неверен. Правильный ответ - это невозможно. Или чтобы соответствовать этому ответу. Это невозможно, но вот хак, чтобы попытаться смоделировать его, который может работать, а может и не работать для вас. - person Jan; 04.09.2015
comment
Я видел людей, которые просили разъяснений по этому и другим связанным с ним вопросам ... * почему * браузер не может получить доступ к текущим заголовкам страниц? Есть ли где-то спецификация браузера, в которой говорится «нет» и, возможно, объясняется причина? - person dstelow; 08.06.2018

К сожалению, не существует API, который предоставил бы вам заголовки HTTP-ответа для вашего начального запроса страницы. Это был исходный вопрос, размещенный здесь. Это неоднократно спросил, потому что некоторые люди хотели бы получать фактические заголовки ответа исходного запроса страницы, не отправляя еще один.


Для запросов AJAX:

Если HTTP-запрос выполняется через AJAX, можно получить заголовки ответа с помощью метода getAllResponseHeaders(). Это часть API XMLHttpRequest. Чтобы увидеть, как это можно применить, ознакомьтесь с функцией fetchSimilarHeaders() ниже. Обратите внимание, что это способ решения проблемы, который не будет надежным для некоторых приложений.

myXMLHttpRequest.getAllResponseHeaders();

Это не даст вам информации о заголовках HTTP-ответа исходного запроса страницы, но его можно использовать для обоснованного предположения о том, что это за заголовки. Подробнее об этом рассказывается далее.


Получение значений заголовка из запроса начальной страницы:

Этот вопрос впервые был задан несколько лет назад, в частности, как получить исходные заголовки HTTP-ответа для текущей страницы (т. Е. Той же страницы, внутри которой был запущен javascript). Это совсем другой вопрос, чем просто получение заголовков ответа на любой HTTP-запрос. Для исходного запроса страницы заголовки недоступны для javascript. Будет ли нужные вам значения заголовка надежно и достаточно согласованными, если вы снова запросите ту же страницу через AJAX, будет зависеть от вашего конкретного приложения.

Ниже приведены несколько советов по решению этой проблемы.


1. Запросы к ресурсам, которые в основном статичны

Если ответ в основном статический и не ожидается, что заголовки сильно изменятся между запросами, вы можете сделать запрос AJAX для той же страницы, на которой вы сейчас находитесь, и предположить, что это те же значения, которые были частью страницы. HTTP-ответ. Это может позволить вам получить доступ к нужным заголовкам с помощью красивого API XMLHttpRequest, описанного выше.

function fetchSimilarHeaders (callback) {
    var request = new XMLHttpRequest();
    request.onreadystatechange = function () {
        if (request.readyState === XMLHttpRequest.DONE) {
            //
            // The following headers may often be similar
            // to those of the original page request...
            //
            if (callback && typeof callback === 'function') {
                callback(request.getAllResponseHeaders());
            }
        }
    };

    //
    // Re-request the same page (document.location)
    // We hope to get the same or similar response headers to those which 
    // came with the current page, but we have no guarantee.
    // Since we are only after the headers, a HEAD request may be sufficient.
    //
    request.open('HEAD', document.location, true);
    request.send(null);
}

Этот подход будет проблематичным, если вам действительно придется полагаться на согласованность значений между запросами, поскольку вы не можете полностью гарантировать, что они одинаковы. Это будет зависеть от вашего конкретного приложения и от того, знаете ли вы, что нужное вам значение не будет меняться от одного запроса к другому.


2. Делать выводы

Есть некоторые свойства спецификации (объектная модель браузера), которые браузер определяет, просматривая заголовки. Некоторые из этих свойств напрямую отражают заголовки HTTP (например, navigator.userAgent устанавливается в значение поля заголовка HTTP User-Agent). Обнюхивая доступные свойства, вы можете найти то, что вам нужно, или некоторые подсказки, чтобы указать, что содержится в ответе HTTP.


3. Спрятать их

Если вы контролируете сторону сервера, вы можете получить доступ к любому заголовку, который вам нравится, при построении полного ответа. Значения могут быть переданы клиенту вместе со страницей, спрятаны в некоторой разметке или, возможно, во встроенной структуре JSON. Если вы хотите, чтобы каждый заголовок HTTP-запроса был доступен для вашего javascript, вы могли бы перебирать их на сервере и отправлять обратно как скрытые значения в разметке. Вероятно, такой способ отправки значений заголовков не идеален, но вы, безусловно, можете сделать это для конкретного значения, которое вам нужно. Возможно, это решение тоже неэффективно, но оно сработает, если вам это нужно.

person keparo    schedule 20.10.2008
comment
Обновление RE: запросы ajax были стандартной частью веб-разработки еще в 2008 году -_- - person BlueRaja - Danny Pflughoeft; 04.02.2012
comment
Для тех, кому интересно, BOM расшифровывается как Browser Object Model. См. stackoverflow.com/questions/2213594/ для некоторого фона. - person Myrne Stol; 28.03.2013
comment
3) вы также можете спрятать их в заголовке http cookie. Тогда вам не нужно будет менять разметку документа. - person skibulk; 26.11.2014
comment
Есть простой способ получить доступ к элементам заголовка ответа, таким как элемент ссылки: используйте здесь пример документа: gist.github.com/FunThomas424242/ - person Huluvu424242; 24.05.2015
comment
Если ваша страница отображается с использованием шаблонов html и вы контролируете код сервера, вы можете спрятать переменные в скрытый div, который javascript может считывать в переменную. ‹Div id = 'myvar' class = 'hide'› {{myvar}} ‹/div› - person intotecho; 17.02.2016
comment
URL-адрес @ Huluvu424242 выдает 404 - person Kumar; 12.08.2020
comment
@Kumar - спасибо за подсказку. Я сменил пользователя для развертываний. Теперь ссылка выглядит так: gist.github.com/Huluvu424242/ - person Huluvu424242; 25.08.2020
comment
Просто добавьте к этому. Теперь вы можете сделать это с помощью функции fetch (), которая поддерживается в Chrome, Edge и Firefox. stevemiller.dev/2019/ - person sproketboy; 19.11.2020

Используя XmlHttpRequest, вы можете открыть текущую страницу, а затем изучить http-заголовки ответа.

В лучшем случае просто выполните HEAD запрос, а затем изучите заголовки.

Некоторые примеры этого можно найти на странице http://www.jibbering.com/2002/4/httprequest.html

Только мои 2 цента.

person Allain Lalonde    schedule 03.11.2008
comment
Именно то, о чем я думал - person FooBar; 08.12.2020

Решение с Service Workers

Сервисные работники могут получить доступ к сетевой информации, включая заголовки. Хорошо то, что он работает с любым запросом, а не только с XMLHttpRequest.

Как это работает:

  1. Добавьте сервисного работника на свой сайт.
  2. Следите за каждым отправляемым запросом.
  3. Сделайте запрос работнику службы fetch с помощью функции respondWith.
  4. Когда придет ответ, прочтите заголовки.
  5. Отправьте заголовки от сервис-воркера на страницу с функцией postMessage.

Рабочий пример:

Сервис-воркеры немного сложны для понимания, поэтому я создал небольшую библиотеку, которая делает все это. Он доступен на github: https://github.com/gmetais/sw-get-headers.

Ограничения:

person Gaël Métais    schedule 11.06.2016
comment
Два основных недостатка ... WKWebView не поддерживает его в Safari 14, последней версии. Другая проблема заключается в том, что в Chrome Incognito есть ярко-синяя кнопка, которая также отключает Service Workers, поскольку большинство людей используют их для хранения вещей ... а не для выполнения важной работы. Сейчас я переключаюсь на рабочих ... но мне кажется, что мне не хватает заголовков 9v1li.csb.app - person Ray Foss; 08.07.2021
comment
Странно ... Я не пропустил заголовки в Service Worker. Я предполагаю, что это могло быть потому, что я был из того же происхождения. Мне просто нужно было добавить еще один заголовок на сервере res.set('Access-Control-Expose-Headers', 'page-size') stackoverflow.com/a/45608476/370238 - person Ray Foss; 08.07.2021

Другой способ отправить информацию заголовка в JavaScript - это файлы cookie. Сервер может извлекать любые данные из заголовков запроса и отправлять их обратно в Set-Cookie заголовке ответа, а файлы cookie можно читать в JavaScript. Однако, как говорит Кепаро, лучше сделать это только для одного или двух заголовков, а не для всех.

person savetheclocktower    schedule 20.10.2008
comment
Этот подход по-прежнему требует, чтобы вы контролировали сервер для вашего JS. Независимо от того, как вы передаете эту информацию, ваш код внезапно стал некэшируемым. Почему бы просто не создать API для этого конкретного запроса, чтобы не повредить запрос на исходный актив? - person MST; 04.07.2016
comment
@MST в моем случае я полностью контролирую прокси, но файлы полностью статически развернуты. Nginx упрощает изменение заголовков. - person Ray Foss; 08.07.2021

Для тех, кто ищет способ преобразовать все заголовки HTTP в объект, к которому можно получить доступ как словарь headers["content-type"], я создал функцию parseHttpHeaders:

function parseHttpHeaders(httpHeaders) {
    return httpHeaders.split("\n")
     .map(x=>x.split(/: */,2))
     .filter(x=>x[0])
     .reduce((ac, x)=>{ac[x[0]] = x[1];return ac;}, {});
}

var req = new XMLHttpRequest();
req.open('GET', document.location, false);
req.send(null);
var headers = parseHttpHeaders(req.getAllResponseHeaders());
// Now we can do:  headers["content-type"]
person Diego    schedule 09.12.2017
comment
Это всегда дает мне доступ, заблокированный политикой CORS: на запрошенном ресурсе отсутствует заголовок Access-Control-Allow-Origin. Как я могу узнать, разрешают ли заголовки iframe или нет? - person mesqueeb; 09.04.2021

Вы не можете получить доступ к заголовкам http, но некоторая информация, представленная в них, доступна в DOM. Например, если вы хотите увидеть http referer (sic), используйте document.referrer. Для других HTTP-заголовков могут быть и другие подобные. Попробуйте поискать в Google конкретную вещь, например "http referer javascript".

Я знаю, что это должно быть очевидно, но я продолжал искать такие вещи, как «http headers javascript», когда все, что мне действительно нужно, это реферер, и не получил никаких полезных результатов. Не знаю, как я не понял, что могу сделать более конкретный запрос.

person David Winiecki    schedule 30.01.2013

Если мы говорим о заголовках Request, вы можете создавать свои собственные заголовки при выполнении XmlHttpRequests.

var request = new XMLHttpRequest();
request.setRequestHeader("X-Requested-With", "XMLHttpRequest");
request.open("GET", path, true);
request.send(null);
person Leo    schedule 21.10.2008
comment
вы не сможете изменить заголовок запроса в Mozilla по соображениям безопасности. mxr.mozilla.org/mozilla1. 8.0 / источник / расширения / xmlextras / base / - person user121196; 13.08.2009
comment
Вы должны вызвать open () перед использованием метода setRequestHeader (). developer.mozilla.org/en/ - person XP1; 09.08.2011
comment
Доступ в исходном вопросе касается получения заголовков, а не их установки. - person Timo Tijhof; 12.02.2016

Как и многие люди, я копался в сети без реального ответа :(

Тем не менее я нашел обходной путь, который может помочь другим. В моем случае я полностью контролирую свой веб-сервер. Фактически это часть моего приложения (см. Конец ссылки). Мне легко добавить скрипт в свой HTTP-ответ. Я модифицировал свой httpd-сервер, чтобы вставлять небольшой скрипт на каждую HTML-страницу. Я только добавляю дополнительную строку 'js script' сразу после создания заголовка, которая устанавливает существующую переменную из моего документа в моем браузере [я выбираю местоположение], но возможен любой другой вариант. Хотя мой сервер написан на nodejs, я не сомневаюсь, что тот же метод можно использовать из PHP или других.

  case ".html":
    response.setHeader("Content-Type", "text/html");
    response.write ("<script>location['GPSD_HTTP_AJAX']=true</script>")
    // process the real contend of my page

Теперь все html-страницы, загруженные с моего сервера, выполняются браузером при приеме. Затем я могу легко проверить с помощью JavaScript, существует ли переменная или нет. В моем случае мне нужно знать, следует ли использовать профиль JSON или JSON-P, чтобы избежать проблемы CORS, но тот же метод можно использовать для других целей [например: выбор между сервером разработки / производства, получение с сервера REST / API ключ и т.д ....]

В браузере вам просто нужно проверить переменную непосредственно из JavaScript, как в моем примере, где я использую ее для выбора своего профиля Json / JQuery.

 // Select direct Ajax/Json profile if using GpsdTracking/HttpAjax server otherwise use JsonP
  var corsbypass = true;  
  if (location['GPSD_HTTP_AJAX']) corsbypass = false;

  if (corsbypass) { // Json & html served from two different web servers
    var gpsdApi = "http://localhost:4080/geojson.rest?jsoncallback=?";
  } else { // Json & html served from same web server [no ?jsoncallback=]
    var gpsdApi = "geojson.rest?";
  }
  var gpsdRqt = 
      {key   :123456789 // user authentication key
      ,cmd   :'list'    // rest command
      ,group :'all'     // group to retreive
      ,round : true     // ask server to round numbers
   };
   $.getJSON(gpsdApi,gpsdRqt, DevListCB);

Для тех, кто когда-либо хотел проверить мой код: https://www.npmjs.org/package/gpsdtracking

person Fulup    schedule 15.10.2014

Ссылка Аллена Лалонда сделала мой день лучше. Просто добавьте сюда простой рабочий HTML-код.
Работает с любым разумным браузером, начиная с IE9 + и Presto-Opera 12.

<!DOCTYPE html>
<title>(XHR) Show all response headers</title>

<h1>All Response Headers with XHR</h1>
<script>
 var X= new XMLHttpRequest();
 X.open("HEAD", location);
 X.send();
 X.onload= function() { 
   document.body.appendChild(document.createElement("pre")).textContent= X.getAllResponseHeaders();
 }
</script>

Примечание: вы получаете заголовки второго запроса, результат может отличаться от исходного запроса.


Другой способ
- это более современный fetch() API
https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
Per caniuse.com он поддерживается Firefox 40, Chrome 42, Edge 14, Safari 11
Рабочий пример кода:

<!DOCTYPE html>
<title>fetch() all Response Headers</title>

<h1>All Response Headers with fetch()</h1>
<script>
 var x= "";
 if(window.fetch)
    fetch(location, {method:'HEAD'})
    .then(function(r) {
       r.headers.forEach(
          function(Value, Header) { x= x + Header + "\n" + Value + "\n\n"; }
       );
    })
    .then(function() {
       document.body.appendChild(document.createElement("pre")).textContent= x;
    });
 else
   document.write("This does not work in your browser - no support for fetch API");
</script>
person j.j.    schedule 10.11.2019

Ответ без дополнительного HTTP-вызова

Хотя в целом невозможно прочитать произвольные заголовки HTTP-ответа для HTML-навигации верхнего уровня, если вы управляете сервером (или промежуточными ящиками по пути) и хотите предоставить некоторую информацию для JavaScript, который может ' t легко раскрыть любым другим способом, кроме как через заголовок:

Вы можете использовать заголовок Server-Timing для предоставления произвольных данных "ключ-значение", которые будут доступны для чтения JavaScript.

(* в поддерживаемых браузерах: Firefox 61, Chrome 65, Edge 79; Safari еще нет с 2021.02; нет IE)

Пример:

server-timing: key;desc="value"
server-timing: key1;desc="value1"
server-timing: key2;desc="value2"
  • или используйте его компактную версию, в которой вы представляете несколько фрагментов данных в одном заголовке, разделенных запятыми.
server-timing: key1;desc="value1", key2;desc="value2"

Пример того, как Википедия использует этот заголовок для отображения информации о попадании / пропуске кеша:

Использование заголовка ответа с синхронизацией сервера в Википедии

Пример кода (необходимо учитывать отсутствие поддержки браузеров в Safari и IE):

if (window.performance && performance.getEntriesByType) { // avoid error in Safari 10, IE9- and other old browsers
    let navTiming = performance.getEntriesByType('navigation')
    if (navTiming.length > 0) { // still not supported as of Safari 14...
        let serverTiming = navTiming[0].serverTiming
        if (serverTiming && serverTiming.length > 0) {
            for (let i=0; i<serverTiming.length; i++) {
                console.log(`${serverTiming[i].name} = ${serverTiming[i].description}`)
            }
        }
    }
}

Это регистрирует cache = hit-front в поддерживаемых браузерах.

Примечания:

  • как упоминалось в MDN, API поддерживается только через HTTPS.
  • если ваш JS обслуживается из другого домена, вам необходимо добавить Заголовок ответа Timing-Allow-Origin, чтобы данные были доступны для чтения в JS (Timing-Allow-Origin: * или Timing-Allow-Origin: https://www.example.com)
  • Заголовки Server-Timing поддерживают также поле dur (заголовок), читаемое как duration на стороне JS, но это необязательно и по умолчанию 0 в JS, если не передано
  • относительно поддержки Safari: см. ошибку 1 и ошибка 2 и ошибка 3
  • Вы можете узнать больше о синхронизации сервера в этом сообщении в блоге
  • Обратите внимание, что буферы записей производительности могут быть очищены JS на странице (через вызов API) или браузером, если страница выдает слишком много вызовов для подресурсов. По этой причине вам следует как можно скорее записать данные и / или вместо этого использовать PerformanceObserver API. Подробнее см. в блоге.
person jakub.g    schedule 15.02.2021

Я только что протестировал, и у меня это работает с использованием Chrome версии 28.0.1500.95.

Мне нужно было загрузить файл и прочитать имя файла. Имя файла указано в заголовке, поэтому я сделал следующее:

var xhr = new XMLHttpRequest(); 
xhr.open('POST', url, true); 
xhr.responseType = "blob";
xhr.onreadystatechange = function () { 
    if (xhr.readyState == 4) {
        success(xhr.response); // the function to proccess the response

        console.log("++++++ reading headers ++++++++");
        var headers = xhr.getAllResponseHeaders();
        console.log(headers);
        console.log("++++++ reading headers end ++++++++");

    }
};

Выход:

Date: Fri, 16 Aug 2013 16:21:33 GMT
Content-Disposition: attachment;filename=testFileName.doc
Content-Length: 20
Server: Apache-Coyote/1.1
Content-Type: application/octet-stream
person rushmore    schedule 16.08.2013

Это мой сценарий для получения всех заголовков ответов:

var url = "< URL >";

var req = new XMLHttpRequest();
req.open('HEAD', url, false);
req.send(null);
var headers = req.getAllResponseHeaders();

//Show alert with response headers.
alert(headers);

Получив в результате заголовки ответа.

введите здесь описание изображения

Это сравнительный тест с использованием Hurl.it:

введите здесь описание изображения

person Jorgesys    schedule 12.12.2017

Чтобы получить заголовки как более удобный объект (улучшение ответа Раджи):

var req = new XMLHttpRequest();
req.open('GET', document.location, false);
req.send(null);
var headers = req.getAllResponseHeaders().toLowerCase();
headers = headers.split(/\n|\r|\r\n/g).reduce(function(a, b) {
    if (b.length) {
        var [ key, value ] = b.split(': ');
        a[key] = value;
    }
    return a;
}, {});
person shaedrich    schedule 14.08.2018

Используя mootools, вы можете использовать this.xhr.getAllResponseHeaders()

person Community    schedule 10.11.2008

Это старый вопрос. Не уверен, когда поддержка станет более широкой, но теперь getAllResponseHeaders() и getResponseHeader() кажутся довольно стандартными: http://www.w3schools.com/xml/dom_http.asp

person dlo    schedule 31.01.2011
comment
getAllResponseHeaders () и getResponseHeader () - это методы объекта XMLHttpRequest. Т.е. для запросов ajax. Вы не можете использовать эти методы для просмотра заголовков начальной страницы - это то, что, я думаю, действительно задавал исходный вопрос. - person asgeo1; 18.04.2011

Как уже упоминалось, если вы контролируете серверную часть, тогда должна быть возможность отправить первоначальные заголовки запроса обратно клиенту в первоначальном ответе.

В Express, например, работает следующее:

app.get('/somepage', (req, res) => { res.render('somepage.hbs', {headers: req.headers}); }) Заголовки становятся доступными в шаблоне, поэтому их можно скрыть визуально, но включить в разметку и прочитать клиентским javascript.

person Ollie Williams    schedule 25.03.2018
comment
Вопрос касается заголовков ответа, а не заголовков запросов. - person Quentin; 05.12.2018

Я думаю, что вопрос пошел неверным путем. Если вы хотите взять заголовок запроса из JQuery / JavaScript, ответ будет просто Нет. Другие решения - создать страницу aspx или страницу jsp, тогда мы можем легко получить доступ к заголовку запроса. Возьмите весь запрос на странице aspx и поместите в сеанс / файлы cookie, после чего вы сможете получить доступ к файлам cookie на странице JavaScript ..

person Santhosh N    schedule 05.12.2018
comment
Вопрос касается чтения заголовков ответа. Заголовки запроса упоминаются только в контексте, возможно, связанного вопроса. - person Quentin; 05.12.2018