【问题标题】:Accessing the web page's HTTP Headers in JavaScript在 JavaScript 中访问网页的 HTTP 标头
【发布时间】:2010-09-18 05:26:26
【问题描述】:

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

this question 相关,已修改为询问有关访问两个特定 HTTP 标头的问题。

相关:
How do I access the HTTP request header fields via JavaScript?

【问题讨论】:

  • @user2284570 — 不是。这个问题是关于 response 标头,而不是 request 标头。
  • 虽然您无法在 JS 中准备 任何标头的 HTML 响应,但您可以读取 Server-Timing 标头,并且可以传递任意键-通过它的价值数据。见my answer
  • 我知道这并不能回答问题,但仍然可以帮助某人。在某些情况下,您可以控制页面内容并可以访问服务器上的标题数据,您可以添加包含所需信息的隐藏元素。

标签: javascript http http-headers


【解决方案1】:

(2021) 答案没有额外的 HTTP 调用

虽然一般不可能读取顶级 HTML 导航的任意 HTTP 响应标头,但如果您控制服务器(或中间框)并希望向 JavaScript 公开一些信息除了通过标头之外,其他任何方式都无法轻易暴露:

您可以使用Server-Timing 标头公开任意键值数据,并且可以被JavaScript 读取。

(*在支持的浏览器中:Firefox 61、Chrome 65、Edge 79;no Safari yet 并且没有从 2021.09 开始立即发货的计划;没有 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,API 仅支持 HTTPS
  • 如果您的 JS 是从另一个域提供的,则必须添加 Timing-Allow-Origin 响应标头以使数据对 JS 可读(Timing-Allow-Origin: *Timing-Allow-Origin: https://www.example.com
  • Server-Timing headers 还支持 dur(header) 字段,在 JS 端可读为 duration,但它是可选的,如果未通过,则在 JS 中默认为 0
  • 关于 Safari 支持:请参阅 bug 1bug 2bug 3
  • 您可以在this blog post 阅读更多关于服务器计时的信息
  • 请注意,如果页面对子资源发出过多调用,性能条目缓冲区可能会被页面上的 JS(通过 API 调用)或浏览器清理。因此,您应该尽快捕获数据,和/或改用PerformanceObserver API。详情请参阅blog post

【讨论】:

    【解决方案2】:

    使用mootools,可以使用this.xhr.getAllResponseHeaders()

    【讨论】:

      【解决方案3】:

      将标头作为更方便的对象获取(Raja's answer 的改进):

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

      【讨论】:

        【解决方案4】:

        Alllain Lalonde 的链接让我很开心。 只需在此处添加一些简单的工作 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
        根据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>
        

        【讨论】:

          【解决方案5】:

          使用 Service Worker 的解决方案

          Service Worker 能够访问网络信息,其中包括标头。好的部分是它适用于任何类型的请求,而不仅仅是 XMLHttpRequest。

          工作原理:

          1. 在您的网站上添加服务人员。
          2. 监视正在发送的每个请求。
          3. 使用respondWith 函数使服务工作者fetch 发出请求。
          4. 响应到达时,读取标头。
          5. 使用postMessage 函数将标头从服务工作者发送到页面。

          工作示例:

          Service Worker 的理解有点复杂,所以我构建了一个小型库来完成所有这些工作。它在 github 上可用:https://github.com/gmetais/sw-get-headers

          限制:

          • 网站需要使用 HTTPS
          • 浏览器需要支持Service Workers API
          • 同域/跨域策略在起作用,就像在 XMLHttpRequest 上一样

          【讨论】:

          • 两个主要缺点... WKWebView 在最新的 safari 14 上不支持它。另一个问题是 Chrome Incognito 上有一个亮蓝色按钮,它也会禁用 Service Worker,因为大多数人使用它们来存储东西......而不是做关键工作。我现在只换工作人员......但我似乎缺少标题9v1li.csb.app
          • 这很奇怪...我没有丢失 Service Worker 中的标头。我想这可能是因为我的出身相似。我只需要在服务器上添加另一个标题res.set('Access-Control-Expose-Headers', 'page-size')stackoverflow.com/a/45608476/370238
          【解决方案6】:

          很遗憾,没有 API 可以为您的初始页面请求提供 HTTP 响应标头。这是此处发布的原始问题。也是repeatedly asked,因为有些人希望得到原始页面请求的实际响应头而不发出另一个。


          对于 AJAX 请求:

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

          myXMLHttpRequest.getAllResponseHeaders();
          

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


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

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

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


          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 标头(例如,navigator.userAgent 设置为 HTTP User-Agent 标头字段的值)。通过嗅探可用的属性,您可能能够找到您需要的东西,或者一些线索来指示 HTTP 响应包含什么。


          3。把它们藏起来

          如果您控制服务器端,则可以在构建完整响应时访问您喜欢的任何标头。值可以与页面一起传递给客户端,隐藏在一些标记中,或者可能是内联的 JSON 结构。如果您想让每个 HTTP 请求标头都可用于您的 javascript,您可以在服务器上遍历它们并将它们作为隐藏值发送回标记中。以这种方式发送标头值可能并不理想,但您当然可以针对您需要的特定值执行此操作。这个解决方案也可以说是低效的,但如果你需要它,它可以完成这项工作。

          【讨论】:

          【解决方案7】:

          我认为这个问题走错了路, 如果您想从 JQuery/JavaScript 中获取请求标头,答案是否定的。其他解决方案是创建一个 aspx 页面或 jsp 页面,然后我们可以轻松访问请求标头。 将 aspx 页面中的所有请求放入 session/cookies 中,然后您就可以访问 JavaScript 页面中的 cookie..

          【讨论】:

          • 问题是关于阅读 response 标题。它仅在可能相关问题的上下文中提及请求标头。
          【解决方案8】:

          正如已经提到的,如果您控制服务器端,那么应该可以在初始响应中将初始请求标头发送回客户端。

          例如,在 Express 中,以下工作:

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

          【讨论】:

          • 问题是询问 response 标头,而不是请求标头。
          【解决方案9】:

          这是我获取所有响应头的脚本:

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

          【讨论】:

            【解决方案10】:

            对于那些寻求将所有 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"]
            

            【讨论】:

            • 这总是给我“访问已被 CORS 策略阻止:请求的资源上不存在‘Access-Control-Allow-Origin’标头。”我如何知道标头是否允许 iframe?
            【解决方案11】:

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

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

            【讨论】:

            【解决方案12】:

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


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

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

            【讨论】:

            • Saeed,也许对问题作者来说不是最好的。我猜这是因为它不访问已加载资源的标头,而是发出新请求。显然他知道最好的,最好的答案是什么是,并自己做的
            • 根据您的标题,您可能需要使用“HEAD”动词。
            • 只有在保证您需要的响应值从一个请求到下一个请求是相同的情况下,才能发出新请求。这取决于您的应用程序,因此您使用这种方法的效果会有所不同。
            • 这个 hack 可能在某些情况下有效,但如果包含脚本的页面是为响应 POST 请求而生成的,它根本不起作用,如果你正在尝试它也无济于事确定服务器在处理原始请求时是否遇到错误(HTTP 5XX)。
            • 这个答案大错特错。正确答案是“不可能”。或者为了适应这个答案“这是不可能的,但这是一个尝试模拟它的黑客,它可能对你有用,也可能对你根本不起作用”。
            【解决方案13】:

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

            【讨论】:

              【解决方案14】:

              这是一个老问题。不确定何时支持变得更广泛,但 getAllResponseHeaders()getResponseHeader() 现在似乎相当标准:http://www.w3schools.com/xml/dom_http.asp

              【讨论】:

              • getAllResponseHeaders() 和 getResponseHeader() 是 XMLHttpRequest 对象的方法。 IE。用于 ajax 请求。您不能使用这些方法来查看初始页面的标题 - 我认为这是最初的问题真正要问的。
              【解决方案15】:

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

              不过,我还是找到了可以帮助其他人的绕过方法。就我而言,我完全控制了我的网络服务器。事实上,它是我的应用程序的一部分(见最终参考)。我很容易将脚本添加到我的 http 响应中。我修改了我的 httpd 服务器以在每个 html 页面中注入一个小脚本。我只在我的标题构造之后推送一个额外的“js脚本”行,它在我的浏览器中从我的文档中设置一个现有变量[我选择位置],但任何其他选项都是可能的。虽然我的服务器是用 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

              【讨论】:

                【解决方案16】:

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

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

                有关执行此操作的一些示例,请查看http://www.jibbering.com/2002/4/httprequest.html

                只要我的 2 美分。

                【讨论】:

                • 跟我想的一模一样
                【解决方案17】:

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

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

                【讨论】:

                  【解决方案18】:

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

                  【讨论】:

                  • 这种方法仍然需要你为你的 JS 控制服务器。无论您如何传达该信息,您的代码都会突然变得不可缓存。为什么不为该特定请求创建一个 API 以避免破坏对原始资产的请求?
                  • @MST 在我的情况下,我可以完全控制代理,但文件完全是静态部署的。 Nginx 使更改标头变得微不足道。
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2014-12-07
                  相关资源
                  最近更新 更多