代码之家  ›  专栏  ›  技术社区  ›  keparo bshirley

在JavaScript中访问网页的HTTP标头

  •  486
  • keparo bshirley  · 技术社区  · 16 年前

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

    关联到 this question ,它被修改为询问访问两个特定的HTTP标头。

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

    18 回复  |  直到 8 年前
        1
  •  396
  •   Randy    8 年前

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


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

    var req = new XMLHttpRequest();
    req.open('GET', document.location, false);
    req.send(null);
    var headers = req.getAllResponseHeaders().toLowerCase();
    alert(headers);
    
        2
  •  322
  •   Community CDub    5 年前

    遗憾的是,没有API为您的初始页面请求提供HTTP响应头。这是这里发布的原始问题。它已经 repeatedly asked 同样,因为有些人希望在不发出另一个页面请求的情况下获得原始页面请求的实际响应头。


    对于AJAX请求:

    如果通过AJAX发出HTTP请求,则可以使用 getAllResponseHeaders() 方法。它是XMLHttpRequest API的一部分。要了解如何应用此功能,请查看 fetchSimilarHeaders() 下面的功能。请注意,这是一种解决问题的方法,对于某些应用程序来说并不可靠。

    myXMLHttpRequest.getAllResponseHeaders();
    

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


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

    这个问题在几年前首次被提出,具体询问如何获取原始HTTP响应头 当前页面 (即运行javascript的同一页面)。这是一个与简单地获取任何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结构中。如果你想让你的javascript使用每个HTTP请求头,你可以在服务器上迭代它们,并将它们作为标记中的隐藏值发送回来。以这种方式发送标头值可能并不理想,但您当然可以为所需的特定值这样做。这个解决方案也可以说效率低下,但如果你需要的话,它可以完成工作。

        3
  •  31
  •   Marius Bancila    11 年前

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

    最好的办法就是做一个 HEAD 请求,然后检查标头。

    关于这样做的一些例子,请看 http://www.jibbering.com/2002/4/httprequest.html

    只有我的2美分。

        4
  •  30
  •   Gaël Métais    6 年前

    服务工作者的解决方案

    服务工作者能够访问网络信息,其中包括标头。好的一面是,它适用于任何类型的请求,而不仅仅是XMLHttpRequest。

    它是如何工作的:

    1. 在您的网站上添加服务人员。
    2. 查看正在发送的每个请求。
    3. 让服务工作者 fetch 请求与 respondWith 功能。
    4. 当响应到达时,读取标题。
    5. 将标头从服务工作器发送到包含 postMessage 功能。

    工作示例:

    服务人员的理解有点复杂,所以我建了一个小图书馆来做这一切。它可以在github上找到: https://github.com/gmetais/sw-get-headers .

    限制:

    • 网站需要在 HTTPS协议
    • 浏览器需要支持 Service Workers API
    • 相同的域/跨域策略正在运行,就像XMLHttpRequest一样
        5
  •  18
  •   savetheclocktower    16 年前

    (2021)答案 没有 额外的HTTP调用(适用于除Safari之外的所有地方)

    虽然这是不可能的 一般说来 读取顶级HTML导航的任意HTTP响应头,如果您控制服务器(或途中的中间箱)并希望向JavaScript公开一些信息,而这些信息除了通过头之外无法通过其他方式轻松公开:

    您可以使用 Server-Timing header公开任意键值数据,JavaScript可以读取。

    (*在支持的浏览器中:Firefox 61、Chrome 65、Edge 79;没有IE, no Safari yet 截至2021年9月,没有立即发货的计划;虽然 it may be implemented for same-origin JS 一天)

    例子:

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

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

    Usage of server-timing response header on 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 )
    • 服务器计时 headers支持 dur (标题)字段,可读为 duration 在JS端,但它是可选的,默认为 0 如果未通过,则在JS中
    • 关于Safari支持:请参阅 bug 1 bug 2 bug 3
    • 您可以在中阅读有关服务器计时的更多信息 this blog post
    • 请注意,如果页面对子资源发出过多的调用,则性能条目缓冲区可能会被页面上的JS(通过API调用)或浏览器清除。因此,您应该尽快捕获数据,和/或使用 PerformanceObserver 改为API。请参阅 blog post 了解详情。
        6
  •  14
  •   Diego    7 年前

    向JavaScript发送标头信息的另一种方式是通过Cookie。服务器可以从请求头中提取所需的任何数据,并将其发送回 Set-Cookie 响应头和Cookie可以在JavaScript中读取。不过,正如凯帕罗所说,最好只对一两个头球这样做,而不是对所有头球都这样做。

        7
  •  7
  •   jakub.g    4 年前

    对于那些寻找将所有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"]
    
        8
  •  6
  •   David Winiecki    12 年前

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

    我知道这应该是显而易见的,但我一直在搜索“http headers javascript”之类的东西,而我真正想要的是引用者,但没有得到任何有用的结果。我不知道为什么我没有意识到我可以提出更具体的问题。

        9
  •  5
  •   user4020527 Leo    7 年前

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

    尽管如此,我还是找到了一种可以帮助他人的旁路。在我的情况下,我完全控制我的网络服务器。事实上,它是我应用程序的一部分(见最终参考)。对我来说,在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

        10
  •  4
  •   Fulup    11 年前

    Allain Lalonde的链接让我度过了美好的一天。 只是在这里添加一些简单的html代码。
    适用于任何合理的浏览器,加上IE9+和Presto-Opera12。

    <!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 它由Firefox40、Chrome42、Edge14、Safari11支持
    工作示例代码:
    <!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>
    
        11
  •  4
  •   j.j.    5 年前

    如果我们谈论的是 要求 headers,您可以在执行XmlHttpRequests时创建自己的headers。

    var request = new XMLHttpRequest();
    request.setRequestHeader("X-Requested-With", "XMLHttpRequest");
    request.open("GET", path, true);
    request.send(null);
    
        12
  •  4
  •   shaedrich Gabin traverse    4 年前

    将标头作为更方便的对象获取(改进 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;
    }, {});
    
        13
  •  3
  •   mkj java seeker    8 年前

    我刚刚进行了测试,使用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
  •  3
  •   Jorgesys    7 年前

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

    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);
    

    因此,具有响应标头。

    enter image description here

    这是一个使用Hurl.it的比较测试:

    enter image description here

        15
  •  3
  •   shaedrich Gabin traverse    4 年前

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

        16
  •  -1
  •   Wilt    9 年前

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

        17
  •  -1
  •   Ollie Williams    7 年前

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

    例如,在Express中,以下操作有效:

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

        18
  •  -2
  •   Santhosh N    6 年前

    我认为这个问题走错了路, 如果你想从JQuery/JavaScript中获取Request标头,答案就是否定的。其他解决方案是创建一个aspx页面或jsp页面,这样我们就可以很容易地访问请求标头。 将aspx页面中的所有请求放入会话/cookies中,然后您可以在JavaScript页面中访问Cookie。。

    推荐文章