简体   繁体   English

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

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

How to check if jQuery.ajax() request header Status is "304 Not Modified"? 如何检查jQuery.ajax()请求标头状态是否为“ 304未修改”?

jqXHR.status usually returns 200 , even when requested header is "304 Not Modified". 即使请求的标头为“ 304 Not Modified”, jqXHR.status通常也返回200

ifModified:true does not help a lot because it breaks XHR data request. ifModified:true 并没有太大帮助,因为它中断了XHR数据请求。

Without handling cache headers manually, it is not possible. 如果不手动处理高速缓存头,则不可能。 Normally, 304 responses are not made available through the XHR API : 通常, XHR API无法提供304个响应:

For 304 Not Modified responses that are a result of a user agent generated conditional request the user agent must act as if the server gave a 200 OK response with the appropriate content . 对于由于用户代理生成的条件请求产生的304未修改响应, 用户代理必须像服务器给出200 OK响应并提供适当的内容一样起作用

jQuery normally doesn't know there was a 304 response, because the browser tells polite lies to JavaScript about what is actually happening over the network. jQuery通常不知道响应是304,因为浏览器告诉JavaScript礼貌的谎言是网络上实际发生的事情。

But there is good news (kind of): you can get Ajax to produce a 304 response, but only by manually setting the HTTP cache headers If-Modified-Since or If-None-Match in the request: 但是有个好消息:您可以让Ajax产生304响应,但只能通过在请求中手动设置HTTP缓存标头 If-Modified-SinceIf-None-Match

The user agent must allow setRequestHeader() to override automatic cache validation by setting request headers (eg, If-None-Match , If-Modified-Since ), in which case 304 Not Modified responses must be passed through. 用户代理必须允许setRequestHeader()通过设置请求标头(例如If-None-MatchIf-Modified-Since setRequestHeader()来覆盖自动缓存验证,在这种情况下,必须传递304 Not Modified响应。

So, you can use code like: 因此,您可以使用如下代码:

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

One fundamental difficulty is how do you know what last-modified date or ETag to send? 一个基本的困难是您如何知道要发送的最后修改日期或ETag The browser has cache information that it uses for sending requests, but it won't share that information with JavaScript. 该浏览器具有用于发送请求的缓存信息,但不会与JavaScript共享该信息。 Fortunately, jQuery keeps track of the Last-Modified and ETag headers from Ajax responses, so you can use ifModified:true to have jQuery set those header values the next time it sends a request for that resource. 幸运的是,jQuery跟踪Ajax响应中的Last-ModifiedETag标头,因此您可以使用ifModified:true使jQuery在下次发送对该资源的请求时设置这些标头值。

Two things to note about this: 需要注意的两件事:

  • 304 responses do not carry data. 304个响应不携带数据。 This is by design. 这是设计使然。 The assumption is that if you have elected to use caching, you should have a copy of the data already in your cache ! 假设是,如果您选择使用缓存,则应该在缓存中已经有一个数据副本 If getting no data from the sever is a problem (ie, because you don't already have that data) why are you using caching? 如果没有从服务器获取数据是一个问题(即,因为您还没有该数据),为什么要使用缓存? Caching should be used when you have the old data on hand and only want new data; 当您手头有旧数据而只需要新数据时,应使用缓存。 thus, getting back no data with a 304 should not be a problem. 因此,使用304取回任何数据应该不是问题。

  • jQuery must have a last-modified date or an ETag (to use with If-None-Match ) stored from a previous request. jQuery必须具有从前一个请求存储的上次修改日期或ETag(用于If-None-Match )。 The process goes like this: 过程如下:

    • First fetch: jQuery has no cache information, so it doesn't send If-Modified-Since or If-None-Match . 首先获取:jQuery没有缓存信息,因此它不会发送If-Modified-SinceIf-None-Match When the response comes back, the server may announce a last-modified data or an ETag, which jQuery stores for future use. 当响应返回时,服务器可以宣布jQuery存储以供将来使用的最后修改的数据或ETag。

    • Subsequent fetches: jQuery has cache information from the last fetch and forwards that data to the server. 后续提取:jQuery具有上一次提取的缓存信息,并将该数据转发到服务器。 If the resource has not changed, the Ajax request gets a 304 response. 如果资源没有更改,则Ajax请求将获得304响应。 If the resource has changed, the Ajax request gets a 200 response, along with new cache information for jQuery to use for its next fetch. 如果资源已更改,则Ajax请求将获得200响应,以及jQuery的新缓存信息以用于下一次提取。

    • jQuery does not persist cache information (eg, in cookies) between page reloads, however. 但是,jQuery在页面重装之间不会保留缓存信息(例如,在cookie中)。 Therefore, the first fetch of a resource after a page reload will never be a 304, because jQuery has no cache information to send (ie, we reset back to the "first fetch" case). 因此,由于jQuery没有要发送的缓存信息,因此页面重新加载后对资源的首次获取将永远不会是304(即,我们将其重置为“首次获取”的情况)。 There is no reason why jQuery couldn't persist cache information, but at present it doesn't. jQuery没有理由不能持久化缓存信息,但是目前没有。

The bottom line here is that you can use cache headers to get a JavaScript 304 response, but you can't access the browser's own ETag or last-modified date for a particular resource. 最重要的是,您可以使用缓存标头来获取JavaScript 304响应,但是您不能访问浏览器自己的 ETag或特定资源的最后修改日期。 So, the browser itself might know caching information about a resource, but your JavaScript code does not. 因此,浏览器本身可能知道有关资源的缓存信息,但是您的JavaScript代码却不知道。 In that case, the browser will use its cache headers to potentially get a real 304 response, but forward a 200 response to your JavaScript code, because JavaScript didn't send any cache information. 在这种情况下,浏览器将使用其缓存标头潜在地获得真实的304响应,但是将200响应转发给您的JavaScript代码,因为JavaScript没有发送任何缓存信息。

It is not possible to make JavaScript 304 requests align perfectly with actual network 304 responses, because the cache information known by your browser and the cache information known by your JavaScript code may differ in unpredictable ways. 不可能使JavaScript 304请求与实际的网络304响应完全匹配,因为浏览器已知的缓存信息和JavaScript代码已知的缓存信息可能会以不可预测的方式不同。 However, getting 304 requests correctly most of the time is good enough for most practical development needs. 但是,大多数时候正确地获取304个请求足以满足大多数实际的开发需求。

Example

Here's a brief server example written in Node.js (but it should be simple enough to port to other langauges): 这是一个用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);

When running this server, you can load the page in your browser and perform two different tests in your browser console: 运行此服务器时,可以在浏览器中加载页面并在浏览器控制台中执行两个不同的测试:

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

This script will always see a 200 response, even if the browser supplies a If-Modified-Since request header and gets a 304 (which will happen all requests after the first, after the browser sees the server's Last-Modifed response header). 这个脚本总会看到一个200响应,即使浏览器提供了一个If-Modified-Since请求头,并得到一个304 (这将发生后的第一个所有请求,浏览器看到服务器的后Last-Modifed响应报头)。

By contrast, this script will always see 304 response: 相比之下,此脚本将始终看到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); }

The script supplies its own If-Modified-Since request header (two days after the server's last-modified date); 该脚本提供了自己的If-Modified-Since请求标头(服务器的上次修改日期后两天)。 it does not rely on whatever the browser supplies for If-Modified-Since , and therefore is allowed (per the XHR spec) to see 304 responses. 它不依赖于浏览器为If-Modified-Since ,因此(根据XHR规范)被允许查看304个响应。

Finally, this script will always see a 200 : 最后,此脚本将始终显示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); }

This is because the script uses a If-Modified-Since that is prior to the server's last-modified date, so the server always sends a 200 . 这是因为脚本使用的If-Modified-Since早于服务器的上次修改日期,因此服务器始终发送200 The server won't send a 304 because it assumes the client doesn't have a cached copy of the most recent version (ie, the client announces that it's seen changes since Feb 12, but there was a change on Feb 13 that the client apparently hasn't seen). 服务器不会发送304因为它假定客户端没有最新版本的缓存副本(即,客户端宣布自2月12日以来已看到更改,但2月13日存在更改,表明客户端显然还没有看到)。

Also the headers will be cached if the response comes from cache. 另外,如果响应来自缓存,则标题也将被缓存。 I took this as a chance. 我以此为契机。 My server sends a unique md5 header. 我的服务器发送了一个唯一的md5标头。 This has not the same effect like ?query=time(). 效果与?query = time()不同。 Now on JS side verify the lastest md5 header with the current. 现在,在JS端,用当前值验证最新的md5标头。 If you receive the same MD5 header as before the response is coming from cache. 如果您收到与以前相同的MD5标头,则响应来自缓存。 I forgot all about JQuery but saw it's possible to set and read headers. 我忘了所有有关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
}

This is a little bit abuse, because md5 should be a hash for to verify that the 'decoded data are the same data that were initially sent'. 这有点滥用,因为md5应该是用于验证“解码后的数据与最初发送的数据相同”的哈希。

I have kind of implementation in https://github.com/laukstein/ajax-seo/blob/cbed03222d89f6f7e75dc49ce8882c30201bbb86/index.php#L266-274 我在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);
        }
    }
});

Maybe try this? 也许试试这个?

$.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
    }
});

open your browsers inspector and it will show you info on the ajax request, including the status. 打开浏览器检查器,它将显示有关ajax请求的信息,包括状态。

for chrome, right click and choose inspect element, then go to the Network tab. 对于Chrome,请右键单击并选择检查元素,然后转到“网络”标签。

for firefox, just use firebug and follow the same steps. 对于firefox,只需使用firebug并遵循相同的步骤。

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

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