在JavaScript中访问网页的HTTP标头

kep*_*aro 396 javascript http http-headers

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

此问题相关,该问题已修改为询问有关访问两个特定HTTP标头的问题.

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

小智 355

无法读取当前标头.您可以对同一个URL发出另一个请求并读取其标题,但不能保证标题与当前标题完全相同.


使用以下JavaScript代码通过执行get请求获取所有HTTP标头:

var req = new XMLHttpRequest();
req.open('GET', document.location, false);
req.send(null);
var headers = req.getAllResponseHeaders().toLowerCase();
alert(headers);
Run Code Online (Sandbox Code Playgroud)

  • Saeed,也许不是最好的问题作者..我想这是因为它不访问加载资源的标题,但提出了一个新请求..显然他知道最好的,最好的答案是什么,并自己做了 (57认同)
  • 根据您之后的标题,您可能想要使用"HEAD"动词. (17认同)
  • 只有在您需要的响应值保证从一个请求到下一个请求相同时,才能生成新请求.这取决于您的应用程序,因此您使用此类方法的里程数会有所不同. (17认同)
  • 这个答案非常错误.正确答案是"这是不可能的".或者为了适应这个答案"这是不可能的,但这是一个试图模拟它的黑客,它可能或根本不适合你". (9认同)
  • 这种hack可能在某些情况下有效,但如果包含脚本的页面是为了响应POST请求而生成的,那么它根本不起作用,如果你试图确定服务器是否遇到错误它就无济于事(HTTP 5XX)处理原始请求时. (6认同)

kep*_*aro 295

遗憾的是,没有API为您的初始页面请求提供HTTP响应标头.那是这里发布的原始问题.它也一再被问到,因为有些人想要获得原始页面请求的实际响应头而不发出另一个.


对于AJAX请求:

如果通过AJAX发出HTTP请求,则可以使用该getAllResponseHeaders()方法获取响应头.它是XMLHttpRequest API的一部分.要了解如何应用此fetchSimilarHeaders()功能,请查看以下功能.请注意,这是针对某些应用程序无法可靠的问题的解决方法.

myXMLHttpRequest.getAllResponseHeaders();
Run Code Online (Sandbox Code Playgroud)

这不会为您提供有关原始页面请求的HTTP响应标头的信息,但它可以用于对这些标头是什么进行有根据的猜测.接下来将介绍更多相关内容.


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

这个问题是几年前首次提出的,具体询问如何获取当前页面的原始HTTP响应头(即javascript运行的同一页面).这是一个完全不同的问题,而不仅仅是获取任何HTTP请求的响应头.对于初始页面请求,标头不可用于javascript.如果您通过AJAX再次请求同一页面,那么您需要的标头值是否可靠且足够一致将取决于您的特定应用程序.

以下是解决该问题的一些建议.


1.资源请求基本上是静态的

如果响应在很大程度上是静态的,并且请求之间的标题不会发生很大变化,那么您可以针对当前所在的同一页面发出AJAX请求,并假设它们是相同的值,它们是页面的一部分. HTTP响应.这可以允许您使用上面描述的nice 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);
}
Run Code Online (Sandbox Code Playgroud)

如果您真的必须依赖请求之间保持一致的值,那么这种方法会有问题,因为您无法完全保证它们是相同的.这将取决于您的具体应用程序,以及您是否知道您需要的价值不会从一个请求更改为下一个请求.


2.做出推论

一些BOM性质,其浏览器确定通过查看头(浏览器对象模型).其中一些属性直接反映HTTP标头(例如navigator.userAgent,设置为HTTP User-Agent标头字段的值).通过嗅探可用的属性,您可以找到所需的内容,或者一些线索来指示HTTP响应包含的内容.


把它们藏起来

如果您控制服务器端,则可以在构建完整响应时访问任何您喜欢的标头.值可以通过页面传递给客户端,存储在某个标记中,也可以存储在内联的JSON结构中.如果您希望每个HTTP请求标头都可用于您的javascript,您可以在服务器上迭代它们并将它们作为隐藏值发送回标记中.以这种方式发送标头值可能并不理想,但您当然可以针对您需要的特定值执行此操作.这个解决方案也可能效率低下,但是如果你需要的话,它可以胜任.

  • BOM代表"浏览器对象模型",对于那些想知道的人.有关背景信息,请参阅http://stackoverflow.com/questions/2213594/whats-the-difference-between-the-browser-object-model-and-the-document-object-m. (5认同)
  • 谷歌如何检测它,就像我在这里解释的那样:http://stackoverflow.com/questions/7191242/how-can-i-get-and-parse-accept-header-to-get-language-at-javascript (2认同)
  • 3)您也可以将它们隐藏在 http cookie 标头中。那么您就不需要更改文档标记。 (2认同)

All*_*nde 28

使用XmlHttpRequest您可以拉出当前页面,然后检查响应的http标头.

最好的情况是只做一个HEAD请求,然后检查标题.

有关这方面的一些示例,请查看http://www.jibbering.com/2002/4/httprequest.html

只需2美分.


Gaë*_*ais 18

服务工作者的解决方案

服务工作者能够访问包括标题的网络信息.好的部分是它适用于任何类型的请求,而不仅仅是XMLHttpRequest.

这个怎么运作:

  1. 在您的网站上添加服务工作者.
  2. 观察正在发送的每个请求.
  3. fetch使用该respondWith功能使服务工作者成为请求.
  4. 当响应到达时,读取标题.
  5. 将标头从服务工作者发送到具有该postMessage功能的页面.

工作范例:

服务工作者理解起来有点复杂,所以我建立了一个小型库来完成这一切.它可以在github上找到:https://github.com/gmetais/sw-get-headers.

限制:

  • 该网站需要使用HTTPS
  • 浏览器需要支持新的Service Workers API
  • 相同的域/跨域策略正在运行,就像在XMLHttpRequest上一样


Die*_*ego 12

对于那些寻找将所有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"]
Run Code Online (Sandbox Code Playgroud)


sav*_*wer 9

将标头信息发送到JavaScript的另一种方法是通过cookie.服务器可以从请求标头中提取所需的任何数据,并将它们发送回Set-Cookie响应标头 - 并且可以使用JavaScript读取cookie.正如keparo所说,最好只针对一个或两个标题,而不是针对所有标题.

  • 这种方法仍然需要您控制 JS 的服务器。无论您如何传达该信息,您的代码都会突然变得不可缓存。为什么不直接为该特定请求创建一个 API 以避免破坏原始资产的请求呢? (2认同)

jak*_*b.g 7

无需额外 HTTP 调用的答案

虽然这是不可能的,一般读取顶级HTML导航的任意HTTP响应头,如果你控制的服务器(或在路上中间件),并要揭露一些信息给JavaScript不能在任何其他容易暴露方式而不是通过标题:

您可以使用Server-Timingheader 来公开任意键值数据,并且它可以被 JavaScript 读取。

(*在支持的浏览器中:Firefox 61、Chrome 65、Edge 79;截至 2021.02 还没有 Safari;没有 IE)

例子:

server-timing: key;desc="value"
Run Code Online (Sandbox Code Playgroud)
server-timing: key1;desc="value1"
server-timing: key2;desc="value2"
Run Code Online (Sandbox Code Playgroud)
  • 或者使用它的紧凑版本,您可以在一个标头中公开多条数据,以逗号分隔。
server-timing: key1;desc="value1", key2;desc="value2"
Run Code Online (Sandbox Code Playgroud)

Wikipedia如何使用此标头公开有关缓存命中/未命中的信息的示例:

维基百科上服务器计时响应头的使用

代码示例(需要考虑 Safari 和 IE 中缺乏浏览器支持):

server-timing: key;desc="value"
Run Code Online (Sandbox Code Playgroud)

这会登录cache = hit-front支持的浏览器。

笔记:

  • 如 MDN 所述,该 API 仅通过 HTTPS 支持
  • 如果您的 JS 是从另一个域提供的,则必须添加Timing-Allow-Origin响应标头以使数据对 JS 可读(Timing-Allow-Origin: *Timing-Allow-Origin: https://www.example.com
  • Server-Timingheaders 也支持dur(header) 字段,duration在 JS 端可读,但它是可选的,0如果不通过则默认在 JS 中
  • 关于 Safari 支持:请参阅错误 1错误 2错误 3
  • 您可以在此博客文章中阅读有关服务器计时的更多信息
  • 请注意,如果页面对子资源发出过多调用,则性能条目缓冲区可能会被页面上的 JS(通过 API 调用)或浏览器清除。因此,您应该尽快捕获数据,和/或改用PerformanceObserverAPI。有关详细信息,请参阅博客文章


Dav*_*cki 6

您无法访问 http 标头,但其中提供的某些信息在 DOM 中可用。例如,如果您想查看 http 引用器(原文如此),请使用 document.referrer。对于其他 http 标头,可能还有其他类似的。尝试使用谷歌搜索您想要的特定内容,例如“http referer javascript”。

我知道这应该是显而易见的,但是当我真正想要的只是引用者时,我一直在寻找诸如“http headers javascript”之类的东西,但没有得到任何有用的结果。我不知道我怎么没有意识到我可以进行更具体的查询。


Ful*_*lup 6

像许多人一样,我一直在网上挖掘但没有真正的答案:(

尽管如此,我还是找到了可以帮助其他人的绕过方法。就我而言,我完全控制我的网络服务器。事实上,它是我的应用程序的一部分(请参阅最终参考)。对我来说,向我的 http 响应添加脚本很容易。我修改了我的 httpd 服务器以在每个 html 页面中注入一个小脚本。我只在标头构建之后推送额外的“js 脚本”行,该行在浏览器中设置文档中的现有变量[我选择位置],但任何其他选项都是可能的。虽然我的服务器是用 Node.js 编写的,但我毫不怀疑 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
Run Code Online (Sandbox Code Playgroud)

现在,从我的服务器加载的每个 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);
Run Code Online (Sandbox Code Playgroud)

对于想要检查我的代码的人: https ://www.npmjs.org/package/gpsdtracking


j.j*_*.j. 6

阿兰·拉隆德的链接让我很高兴。只需在此处添加一些简单的工作 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>
Run Code Online (Sandbox Code Playgroud)

注意:您会收到第二个请求的标头,结果可能与初始请求不同。


另一种方法
是更现代的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>
Run Code Online (Sandbox Code Playgroud)


Leo*_*Leo 5

如果我们讨论的是Request头,您可以在执行XmlHttpRequests时创建自己的头.

var request = new XMLHttpRequest();
request.setRequestHeader("X-Requested-With", "XMLHttpRequest");
request.open("GET", path, true);
request.send(null);
Run Code Online (Sandbox Code Playgroud)