繁体   English   中英

如何检查jQuery.ajax()请求标头状态是否为“ 304未修改”?

[英]How to check if jQuery.ajax() request header Status is “304 Not Modified”?

如何检查jQuery.ajax()请求标头状态是否为“ 304未修改”?

即使请求的标头为“ 304 Not Modified”, jqXHR.status通常也返回200

ifModified:true 并没有太大帮助,因为它中断了XHR数据请求。

如果不手动处理高速缓存头,则不可能。 通常, XHR API无法提供304个响应:

对于由于用户代理生成的条件请求产生的304未修改响应, 用户代理必须像服务器给出200 OK响应并提供适当的内容一样起作用

jQuery通常不知道响应是304,因为浏览器告诉JavaScript礼貌的谎言是网络上实际发生的事情。

但是有个好消息:您可以让Ajax产生304响应,但只能通过在请求中手动设置HTTP缓存标头 If-Modified-SinceIf-None-Match

用户代理必须允许setRequestHeader()通过设置请求标头(例如If-None-MatchIf-Modified-Since setRequestHeader()来覆盖自动缓存验证,在这种情况下,必须传递304 Not Modified响应。

因此,您可以使用如下代码:

var xhr = new XMLHttpRequest();
xhr.open("GET", "foo.html");
xhr.setRequestHeader("If-Modified-Since", "Fri, 15 Feb 2013 13:43:19 GMT");
xhr.send();

一个基本的困难是您如何知道要发送的最后修改日期或ETag 该浏览器具有用于发送请求的缓存信息,但不会与JavaScript共享该信息。 幸运的是,jQuery跟踪Ajax响应中的Last-ModifiedETag标头,因此您可以使用ifModified:true使jQuery在下次发送对该资源的请求时设置这些标头值。

需要注意的两件事:

  • 304个响应不携带数据。 这是设计使然。 假设是,如果您选择使用缓存,则应该在缓存中已经有一个数据副本 如果没有从服务器获取数据是一个问题(即,因为您还没有该数据),为什么要使用缓存? 当您手头有旧数据而只需要新数据时,应使用缓存。 因此,使用304取回任何数据应该不是问题。

  • jQuery必须具有从前一个请求存储的上次修改日期或ETag(用于If-None-Match )。 过程如下:

    • 首先获取:jQuery没有缓存信息,因此它不会发送If-Modified-SinceIf-None-Match 当响应返回时,服务器可以宣布jQuery存储以供将来使用的最后修改的数据或ETag。

    • 后续提取:jQuery具有上一次提取的缓存信息,并将该数据转发到服务器。 如果资源没有更改,则Ajax请求将获得304响应。 如果资源已更改,则Ajax请求将获得200响应,以及jQuery的新缓存信息以用于下一次提取。

    • 但是,jQuery在页面重装之间不会保留缓存信息(例如,在cookie中)。 因此,由于jQuery没有要发送的缓存信息,因此页面重新加载后对资源的首次获取将永远不会是304(即,我们将其重置为“首次获取”的情况)。 jQuery没有理由不能持久化缓存信息,但是目前没有。

最重要的是,您可以使用缓存标头来获取JavaScript 304响应,但是您不能访问浏览器自己的 ETag或特定资源的最后修改日期。 因此,浏览器本身可能知道有关资源的缓存信息,但是您的JavaScript代码却不知道。 在这种情况下,浏览器将使用其缓存标头潜在地获得真实的304响应,但是将200响应转发给您的JavaScript代码,因为JavaScript没有发送任何缓存信息。

不可能使JavaScript 304请求与实际的网络304响应完全匹配,因为浏览器已知的缓存信息和JavaScript代码已知的缓存信息可能会以不可预测的方式不同。 但是,大多数时候正确地获取304个请求足以满足大多数实际的开发需求。

这是一个用Node.js编写的简短服务器示例(但它应该足够简单以移植到其他语言):

require("http").createServer(function (req, res) {
  console.log(req.headers["if-modified-since"]);

  // always send Last-Modifed header
  var lastModDate = "Fri, 13 Feb 2013 13:43:19 GMT";
  res.setHeader("Last-Modified", lastModDate);

  // if the request has a If-Modified-Since header,
  //   and it's newer than the last modification,
  //   then send a 304 response; otherwise send 200
  if(req.headers["if-modified-since"] &&
     Date.parse(lastModDate) <= Date.parse(req.headers["if-modified-since"])) {
    console.log("304 -- browser has it cached");
    res.writeHead(304, {'Content-Type': 'text/plain'});
    res.end();
  } else {
    console.log("200 -- browser needs it fresh");
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('some content');
  }

}).listen(8080);

运行此服务器时,可以在浏览器中加载页面并在浏览器控制台中执行两个不同的测试:

var xhr = new XMLHttpRequest();
xhr.open("GET", "/");
xhr.send();
xhr.onload = function() { console.log(xhr.status); }

这个脚本总会看到一个200响应,即使浏览器提供了一个If-Modified-Since请求头,并得到一个304 (这将发生后的第一个所有请求,浏览器看到服务器的后Last-Modifed响应报头)。

相比之下,此脚本将始终看到304响应:

var xhr = new XMLHttpRequest();
xhr.open("GET", "/");
xhr.setRequestHeader("If-Modified-Since", "Fri, 15 Feb 2013 13:43:19 GMT");
xhr.send();
xhr.onload = function() { console.log(xhr.status); }

该脚本提供了自己的If-Modified-Since请求标头(服务器的上次修改日期后两天)。 它不依赖于浏览器为If-Modified-Since ,因此(根据XHR规范)被允许查看304个响应。

最后,此脚本将始终显示200

var xhr = new XMLHttpRequest();
xhr.open("GET", "/");
xhr.setRequestHeader("If-Modified-Since", "Fri, 12 Feb 2013 13:43:19 GMT");
xhr.send();
xhr.onload = function() { console.log(xhr.status); }

这是因为脚本使用的If-Modified-Since早于服务器的上次修改日期,因此服务器始终发送200 服务器不会发送304因为它假定客户端没有最新版本的缓存副本(即,客户端宣布自2月12日以来已看到更改,但2月13日存在更改,表明客户端显然还没有看到)。

另外,如果响应来自缓存,则标题也将被缓存。 我以此为契机。 我的服务器发送了一个唯一的md5标头。 效果与?query = time()不同。 现在,在JS端,用当前值验证最新的md5标头。 如果您收到与以前相同的MD5标头,则响应来自缓存。 我忘了所有有关JQuery的知识,但看到可以设置和读取标头。

<?php
$oldMD5=filter_input(INPUT_SERVER,'HTTP_CONTENT_MD5',int);
if(!empty($oldMD5)){
  header('Content-MD5: '.(1+(int)$oldMD5));
}
--------------------------------------------------------------
<script>
var oldMD5=0;
//your Ajax implementation 
Ajax.setRequestHeader('Content-MD5',''+oldMD5);
var newMD5=parseInt(Ajax.getResponseHeader('Content-MD5'),10);
if(newMD5 && oldMD5<newMD5,10){
  oldMD5=newMD5;
  //not cached
}else{
  //cached
}

这有点滥用,因为md5应该是用于验证“解码后的数据与最初发送的数据相同”的哈希。

我在https://github.com/laukstein/ajax-seo/blob/cbed03222d89f6f7e75dc49ce8882c30201bbb86/index.php#L266-274中有一种实现

var cache;

$.ajax({
    ...
    beforeSend: function() {
        cache = setTimeout(function() {
            console.log('The content not cached jet.');
        }, 300);
    },
    success: function(data) {
        if (cache) {
            clearTimeout(cache);
        }
    }
});

也许试试这个?

$.ajax({
    url: 'your-url',
    dataType: 'script',
    complete: function(xhr) { 
        if (xhr.status == 304) return;
        // or better: if (xhr.status != 200) return;
        // your code goes here
    }
});

打开浏览器检查器,它将显示有关ajax请求的信息,包括状态。

对于Chrome,请右键单击并选择检查元素,然后转到“网络”标签。

对于firefox,只需使用firebug并遵循相同的步骤。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM