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

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

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


当前回答

我觉得这个问题问错了, 如果你想从JQuery/JavaScript中获取Request头,答案是No。另一种解决方案是创建一个aspx页面或jsp页面,这样我们就可以很容易地访问请求头。 把aspx页面中的所有请求放到一个会话/cookie中,然后你可以访问JavaScript页面中的cookie。

其他回答

(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.

我刚刚测试过,这适用于我使用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

不幸的是,没有一个API为您的初始页面请求提供HTTP响应头。这是最初的问题。它也被反复要求,因为有些人希望获得原始页面请求的实际响应头,而不需要发出另一个页面请求。

对于AJAX请求:

如果HTTP请求是通过AJAX发出的,则可以使用getAllResponseHeaders()方法获得响应头。它是XMLHttpRequest API的一部分。要了解如何应用它,请查看下面的fetchSimilarHeaders()函数。请注意,这是对某些应用程序不可靠的问题的一种变通方法。

myXMLHttpRequest.getAllResponseHeaders();

该API在以下XMLHttpRequest候选推荐中指定:XMLHttpRequest - W3C候选推荐3 2010年8月 具体来说,getAllResponseHeaders()方法在以下部分中指定 MDN文档也很好:developer.mozilla.org: XMLHttpRequest。

这不会为您提供关于原始页面请求的HTTP响应标头的信息,但可以用来对这些标头进行有根据的猜测。下面将详细介绍。

从初始页面请求中获取头值:

This question was first asked several years ago, asking specifically about how to get at the original HTTP response headers for the current page (i.e. the same page inside of which the javascript was running). This is quite a different question than simply getting the response headers for any HTTP request. For the initial page request, the headers aren't readily available to javascript. Whether the header values you need will be reliably and sufficiently consistent if you request the same page again via AJAX will depend on your particular application.

下面是一些解决这个问题的建议。

1. 对资源的请求大部分是静态的

如果响应基本上是静态的,并且请求之间的报头预计不会有太大变化,那么您可以对当前所在的同一页面发出AJAX请求,并假设它们是页面HTTP响应中的相同值。这允许您使用上面描述的XMLHttpRequest API访问所需的标头。

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. 进行推断

有一些BOM属性(浏览器对象模型)是浏览器通过查看头文件来确定的。其中一些属性直接反映HTTP报头(例如导航器)。userAgent被设置为HTTP User-Agent报头字段的值)。通过嗅探可用属性,您可能能够找到您需要的东西,或者一些指示HTTP响应包含什么的线索。

3.藏

If you control the server side, you can access any header you like as you construct the full response. Values could be passed to the client with the page, stashed in some markup or perhaps in an inlined JSON structure. If you wanted to have every HTTP request header available to your javascript, you could iterate through them on the server and send them back as hidden values in the markup. It's probably not ideal to send header values this way, but you could certainly do it for the specific value you need. This solution is arguably inefficient, too, but it would do the job if you needed it.

这是我的脚本,以获得所有的响应头:

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的对比测试:

如前所述,如果您控制服务器端,那么应该可以在初始响应中将初始请求头发送回客户端。

以Express为例,以下工作:

App.get ('/somepage', (req, res) => { res.render(“somepage。Hbs ', {headers: req.headers}); }) 然后在模板中可以使用头文件,因此可以在视觉上隐藏,但包含在标记中并由客户端javascript读取。