如何通过JavaScript访问页面的HTTP响应头?

与此问题相关,该问题已被修改为询问访问两个特定的HTTP报头。

相关: 如何通过JavaScript访问HTTP请求报头字段?


当前回答

(2021)一个没有额外HTTP调用的应答

一般来说,读取顶级HTML导航的任意HTTP响应头是不可能的,如果你控制了服务器(或中间箱),想要向JavaScript公开一些信息,而这些信息只能通过头来公开:

可以使用Server-Timing报头公开任意键值数据,JavaScript可以读取这些数据。

(*支持的浏览器:Firefox 61, Chrome 65, Edge 79;目前还没有Safari浏览器,也没有在2021年9月发布的计划;没有IE)

例子:

server-timing: key;desc="value"

你可以对多个数据块多次使用这个头文件:

server-timing: key1;desc="value1"
server-timing: key2;desc="value2"

或者使用它的精简版本,在一个标题中公开多个数据,以逗号分隔。

server-timing: key1;desc="value1", key2;desc="value2"

Wikipedia如何使用这个报头来暴露缓存命中/错过的信息:

代码示例(需要考虑在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。

注:

as mentioned on MDN, the API is only supported over HTTPS if your JS is served from another domain, you have to add Timing-Allow-Origin response header to make the data readable to JS (Timing-Allow-Origin: * or Timing-Allow-Origin: https://www.example.com) Server-Timing headers support also dur(header) field, readable as duration on JS side, but it's optional and defaults to 0 in JS if not passed regarding Safari support: see bug 1 and bug 2 and bug 3 You can read more on server-timing in this blog post Note that performance entries buffers might get cleaned by JS on the page (via an API call), or by the browser, if the page issues too many calls for subresources. For that reason, you should capture the data as soon as possible, and/or use PerformanceObserver API instead. See the blog post for details.

其他回答

为了获得头部作为一个更方便的对象(改进Raja的答案):

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;
}, {});

和许多人一样,我一直在网上搜索,没有真正的答案:(

I've nevertheless find out a bypass that could help others. In my case I fully control my web server. In fact it is part of my application (see end reference). It is easy for me to add a script to my http response. I modified my httpd server to inject a small script within every html pages. I only push a extra 'js script' line right after my header construction, that set an existing variable from my document within my browser [I choose location], but any other option is possible. While my server is written in nodejs, I've no doubt that the same technique can be use from PHP or others.

  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

Allain Lalonde的链接让我很开心。 只是在这里添加了一些简单的html代码。 适用于任何合理的浏览器,年龄加上IE9+和preto - 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 根据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>

您不能访问http报头,但是其中提供的一些信息在DOM中是可用的。例如,如果你想查看http引用器(原文如此),使用document.referrer。可能还有其他类似的http头文件。试着谷歌一下你想要的具体内容,比如“http referer javascript”。

我知道这应该是显而易见的,但我一直在搜索像“http headers javascript”这样的东西,而我真正想要的只是引用器,并没有得到任何有用的结果。我不知道我怎么没意识到我可以问个更具体的问题。

(2021)一个没有额外HTTP调用的应答

一般来说,读取顶级HTML导航的任意HTTP响应头是不可能的,如果你控制了服务器(或中间箱),想要向JavaScript公开一些信息,而这些信息只能通过头来公开:

可以使用Server-Timing报头公开任意键值数据,JavaScript可以读取这些数据。

(*支持的浏览器:Firefox 61, Chrome 65, Edge 79;目前还没有Safari浏览器,也没有在2021年9月发布的计划;没有IE)

例子:

server-timing: key;desc="value"

你可以对多个数据块多次使用这个头文件:

server-timing: key1;desc="value1"
server-timing: key2;desc="value2"

或者使用它的精简版本,在一个标题中公开多个数据,以逗号分隔。

server-timing: key1;desc="value1", key2;desc="value2"

Wikipedia如何使用这个报头来暴露缓存命中/错过的信息:

代码示例(需要考虑在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。

注:

as mentioned on MDN, the API is only supported over HTTPS if your JS is served from another domain, you have to add Timing-Allow-Origin response header to make the data readable to JS (Timing-Allow-Origin: * or Timing-Allow-Origin: https://www.example.com) Server-Timing headers support also dur(header) field, readable as duration on JS side, but it's optional and defaults to 0 in JS if not passed regarding Safari support: see bug 1 and bug 2 and bug 3 You can read more on server-timing in this blog post Note that performance entries buffers might get cleaned by JS on the page (via an API call), or by the browser, if the page issues too many calls for subresources. For that reason, you should capture the data as soon as possible, and/or use PerformanceObserver API instead. See the blog post for details.