如何检查 jQuery.ajax() 请求标头状态是否为“304 Not Modified”?
如何检查 jQuery.ajax() 请求标头状态是否为“304 Not Modified”?
jqXHR.status
通常返回 200
,即使请求的标头为“304 Not Modified”。
ifModified:true
没有太大帮助,因为它破坏了 XHR 数据请求。
How to check if jQuery.ajax() request header Status is "304 Not Modified"?
jqXHR.status
usually returns 200
, even when requested header is "304 Not Modified".
ifModified:true
does not help a lot because it breaks XHR data request.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
如果不手动处理缓存标头,这是不可能的。通常,304 响应无法通过 XHR API 提供:
jQuery 通常不知道有 304 响应,因为浏览器会礼貌地向 JavaScript 撒谎,告知网络上实际发生的情况。
但有一个好消息(有点):您可以让 Ajax 生成 304 响应,但只能通过手动设置 请求中的 HTTP 缓存标头
If-Modified-Since
或If-None-Match
:因此,您可以使用如下代码:
一个基本困难是您如何知道上次修改日期或ETag发送? 浏览器具有用于发送请求的缓存信息,但它不会与 JavaScript 共享该信息。幸运的是,jQuery 会跟踪 Ajax 响应中的
Last-Modified
和ETag
标头,因此您可以使用ifModified:true
让 jQuery 设置这些标头下次发送对该资源的请求时标头值。对此需要注意两点:
304 响应不携带数据。这是设计使然。假设是,如果您选择使用缓存,则您的缓存中应该已有数据的副本!!如果无法从服务器获取数据是一个问题(即,因为您还没有该数据),那么为什么要使用缓存?当你手头有旧数据而只需要新数据时,应该使用缓存;因此,使用 304 返回没有数据应该不是问题。
jQuery 必须具有上次请求存储的上次修改日期或 ETag(与
If-None-Match
一起使用)。过程是这样的:首次获取:jQuery 没有缓存信息,因此不会发送
If-Modified-Since
或If-None-Match
。当响应返回时,服务器可能会宣布最后修改的数据或 ETag,jQuery 存储这些数据以供将来使用。后续获取:jQuery 缓存上次获取的信息并将该数据转发到服务器。如果资源未更改,Ajax 请求将收到 304 响应。如果资源已更改,Ajax 请求将收到 200 响应,以及 jQuery 用于下次获取的新缓存信息。
但是,jQuery 不会在页面重新加载之间保留缓存信息(例如,在 cookie 中)。因此,页面重新加载后第一次获取资源将永远不会是 304,因为 jQuery 没有要发送的缓存信息(即我们重置回“第一次获取”情况)。 jQuery 没有理由不能保留缓存信息,但目前它不能。
这里的底线是,您可以使用缓存标头来获取 JavaScript 304 响应,但您无法访问浏览器自己的 ETag 或特定资源的上次修改日期。因此,浏览器本身可能知道缓存有关资源的信息,但您的 JavaScript 代码却不知道。在这种情况下,浏览器将使用其缓存标头来获取真正的 304 响应,但将 200 响应转发到您的 JavaScript 代码,因为 JavaScript 没有发送任何缓存信息。
不可能使 JavaScript 304 请求与实际的网络 304 响应完全一致,因为您的浏览器已知的缓存信息和您的 JavaScript 代码已知的缓存信息可能会以不可预测的方式有所不同。然而,大多数时候正确获取 304 请求对于大多数实际开发需求来说已经足够了。
示例
下面是一个用 Node.js 编写的简短服务器示例(但它应该足够简单,可以移植到其他语言):
运行此服务器时,您可以在浏览器中加载页面并在浏览器控制台中执行两个不同的测试:
此脚本即使浏览器提供
If-Modified-Since
请求标头并获取304
(这将在所有情况下发生),也始终会看到200
响应在浏览器看到服务器的Last-Modifed
响应标头之后的第一个请求之后)。相比之下,此脚本总是看到 304 响应:
该脚本提供自己的
If-Modified-Since
请求标头(服务器上次修改日期后两天);它不依赖于浏览器为If-Modified-Since
提供的任何内容,因此允许(根据 XHR 规范)查看 304 响应。最后,此脚本将始终看到
200
:这是因为该脚本使用早于服务器上次修改日期的
If-Modified-Since
,因此服务器始终发送200
。服务器不会发送304
,因为它假定客户端没有最新版本的缓存副本(即客户端宣布自 2 月 12 日以来已看到更改,但有一个2 月 13 日发生的变化,客户显然没有看到)。Without handling cache headers manually, it is not possible. Normally, 304 responses are not made available through the XHR API:
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.
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
orIf-None-Match
in the request:So, you can use code like:
One fundamental difficulty is how do you know what last-modified date or ETag to send? The browser has cache information that it uses for sending requests, but it won't share that information with JavaScript. Fortunately, jQuery keeps track of the
Last-Modified
andETag
headers from Ajax responses, so you can useifModified:true
to have jQuery set those header values the next time it sends a request for that resource.Two things to note about this:
304 responses do not carry data. 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 (i.e., 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.
jQuery must have a last-modified date or an ETag (to use with
If-None-Match
) stored from a previous request. The process goes like this:First fetch: jQuery has no cache information, so it doesn't send
If-Modified-Since
orIf-None-Match
. When the response comes back, the server may announce a last-modified data or an ETag, which jQuery stores for future use.Subsequent fetches: jQuery has cache information from the last fetch and forwards that data to the server. If the resource has not changed, the Ajax request gets a 304 response. 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.
jQuery does not persist cache information (e.g., in cookies) between page reloads, however. Therefore, the first fetch of a resource after a page reload will never be a 304, because jQuery has no cache information to send (i.e., we reset back to the "first fetch" case). There is no reason why jQuery couldn't persist cache information, but at present it doesn't.
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. So, the browser itself might know caching information about a resource, but your JavaScript code does not. 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.
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. However, getting 304 requests correctly most of the time is good enough for most practical development needs.
Example
Here's a brief server example written in Node.js (but it should be simple enough to port to other langauges):
When running this server, you can load the page in your browser and perform two different tests in your browser console:
This script will always see a
200
response, even if the browser supplies aIf-Modified-Since
request header and gets a304
(which will happen all requests after the first, after the browser sees the server'sLast-Modifed
response header).By contrast, this script will always see 304 response:
The script supplies its own
If-Modified-Since
request header (two days after the server's last-modified date); it does not rely on whatever the browser supplies forIf-Modified-Since
, and therefore is allowed (per the XHR spec) to see 304 responses.Finally, this script will always see a
200
: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 a200
. The server won't send a304
because it assumes the client doesn't have a cached copy of the most recent version (i.e., 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).如果响应来自缓存,则标头也将被缓存。我把这当作一个机会。
我的服务器发送一个唯一的 md5 标头。这与 ?query=time() 的效果不同。现在在 JS 端验证最新的 md5 标头与当前的。如果您收到与之前相同的 MD5 标头,则响应来自缓存。我完全忘记了 JQuery,但看到可以设置和读取标题。
这有点滥用,因为 md5 应该是一个哈希值,用于验证“解码的数据与最初发送的数据相同”。
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. This has not the same effect like ?query=time(). Now on JS side verify the lastest md5 header with the current. If you receive the same MD5 header as before the response is coming from cache. I forgot all about JQuery but saw it's possible to set and read headers.
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'.
我有一种实施
https://github.com/laukstein/ajax-seo /blob/cbed03222d89f6f7e75dc49ce8882c30201bbb86/index.php#L266-274
I have kind of implementation in
https://github.com/laukstein/ajax-seo/blob/cbed03222d89f6f7e75dc49ce8882c30201bbb86/index.php#L266-274
也许试试这个?
Maybe try this?
打开浏览器检查器,它将显示有关 ajax 请求的信息,包括状态。
对于 Chrome,右键单击并选择检查元素,然后转到网络选项卡。
对于 Firefox,只需使用 Firebug 并按照相同的步骤操作即可。
open your browsers inspector and it will show you info on the ajax request, including the status.
for chrome, right click and choose inspect element, then go to the Network tab.
for firefox, just use firebug and follow the same steps.