asp.net页面的304 Not Modified代码与 原理

通过前面的示例,我们已经看到缓存带来的好处:那就是可以减少到服务器的访问,由于不访问服务器就能显示页面,这对于服务器来说, 能减轻一定的访问压力。但是,如果用户强制刷新浏览器,那么浏览器将会忽略缓存页,直接向服务器重新发起请求。

也就是说:缓存页在用户强制刷新浏览器时会无效。

但是,我们之所以使用缓存页,是因为我们希望告诉浏览器:这些数据在一定时间内,并不会发生变化,因此根本不需要再次请求服务器了。 然而,我们不能阻止用户的行为。由于浏览器的重新访问,我们原来设想的缓存想法将会落空,最后的结果是: 页面在服务器中重新执行,产生的HTML代码将重新发送到客户端。而这一重新刷新的结果可能也是无意义的,因为数据可能根本没有发生变化, 因此得到的页面也是不可能有变化的。

再来举个简单的例子来说吧:客户端要浏览一张图片。 当浏览器第一次要访问图片时,浏览器肯定是没有它的任何缓存记录的,此时它去访问服务器,服务器也返回图片的内容了。 但由于图片可能会被多个页面所引用,而它被修改的可能性是很小的。 因此没有必要为同一浏览器的多次请求都去读取图片并返回图片的内容,这样做既影响性能也学浪费带宽。 于是,像IIS这样服务器软件针对这类静态文件的访问时,都会在响应头上输出一些标记,用来告之浏览器这个文件你可以缓存起来了。

还是回到前面所说的【用户强制刷新】问题,此时的IIS又会如何处理呢?请看下图:

注意哦,此时除了HTTP状态码变成304之外,没有任何数据返回哦。

为了让您对304应答有个深刻的印象,我截了一张状态码为200的图片响应结果:

通过这二张图片的对比,现在看清楚了吧:304和200并不只是数字上的差别,最重要的差别在于有没有返回结果。

没有返回结果,浏览器该如何显示?

您会有这样的疑虑吗?

其实不用担心,此时浏览器会使用它缓存版本来显示。也就是说:不管用户如何强制刷,服务器就是不返回结果,但仍然可以正常显示。

显然,这个效果就是我们想要的。

前面所说的缓存页遭用户强刷的问题,如果采用这种方法,就比较完美了。

不过,有一点我要提醒您:Visual Studio自带的那个WebDev.WebServer.exe不支持304应答,所以您就不要拿它试验了,不会有结果的。

回到顶部

如何编程实现304应答

前面我们看到了304应答的效果。不过,在ASP.NET中,我们开发的程序,是动态页面,而不是图片, 我们更希望某个页面能以这种方式缓存一段时间,我想这个需求或许会更有意义。

下面,我就来演示如何通过编程的方式实现它。

接下来的示例中,页面的显示还是那个样,显示页面在服务器上产生的时间,时间变化了,说明页面被重新执行了。

重新截一系列的图片,我认为意义也不大,我就截一张图片展现多次强刷而产生的过程

上图反映了我多次请求某个ASPX页面的过程,从图片中可以看出,只有第一次是200的响应,后面全是304,是您所期待的结果吧。

再来看看它的实现代码吧: 

虽然代码并不复杂,但我还是打算来解释一下:

在浏览器第一次请求页面时,会执行SetLastModified的调用,它会在响应时输出一个"Last-Modified"这个响应头, 然后,当浏览器再次访问这个页面时,会将上次请求所获取的"Last-Modified"头的内容 , 以"If-Modified-Since"这个请求头的形式发给服务端,此时服务器就可以根据具体逻辑来判断要不要使用304应答了。

在前面的请求图片的示例中,服务器以图片文件的最后修改时间做为"Last-Modified"发给浏览器, 浏览器在后续请求那张图片时,又以"If-Modified-Since"的形式告之服务端,此时服务端只要再次检查一下这张图片就知道图片在上次访问后有没有发生修改, 如果没有修改,当然就以304的形式告之浏览器:继续使用缓存版本。

还是前面的请求图片的示例,其实服务端还使用了另一对【请求/响应】头:

这二个头的使用方式是:服务端输出一个ETag头,浏览器在接收后,以If-None-Match的形式在后续请求中发送到服务端, 供服务端判断是否使用304应答。

"Last-Modified"与"ETag"这二者,事实上只需要使用一个就够了,关键还是看服务端如何处理它们,浏览器只是在接收后,下次再发出去而已。

不过,前面的示例代码并没有使用缓存头,事实上,也可以带上它,这样可以尽量减少对服务器的访问,毕竟用户不会一直强刷浏览器。 这二种方式虽然有较大差别,但它们绝对是可以互补的。

为了能形象的描绘缓存页(或者其它文档)的请求过程,我画了张示意图供大家参考:

回到顶部

如何避开HTTP缓存

前面小节中,介绍了二种方法使用浏览器的缓存。但有些时候可能反而希望浏览器能放弃它缓存的结果。 现在的浏览器都有缓存功能,尤其是对一些静态文件,比如:图片,JS,CSS, HTML文件,都能缓存。 但有时候我们需要更新CSS, JS文件呢,浏览器如果还使用它的缓存版本,显然就有问题了。 而且有些网站使用了URL重写,使原来的动态页面扩展名也变成静态的HTML文件了, 因此,仍然希望浏览器在某些时候能够不要缓存这些伪静态页面。

此时,我们就希望浏览器放弃从HTTP请求所获得的结果了。 一般说来,浏览器在处理(它认为的)静态文件时,会按照URL为kEY来保存那些缓存结果, 因此,通常的解决办法也就是修改URL,比如:原来是请求abc.js的,要改成abc.js?t=23434,后面要跟上一个参数, 让以前的缓存不起作用。至于参数t的取值可以根据文件的最后修改时间,也可以手工指定,总之只要改变它就可以了。

但是,对于伪静态的页面,我们不能再使用这种方法了,原因就不用解释了吧。

那么,可以采用在服务端输出一个响应头,通过响应头的方式告之浏览器,不要缓存此文件。 比如,可以调用这个方法:

Response.Cache.SetNoStore();

它会生成这样的响应头内容:

Cache-Control: private, no-store

许多浏览器都能识别它。还有另一种方法是设置一个已过期的过期时间。

前面所说的在URL中加额外参数的做法,在JS中也比较常用,比如 JQuery就支持让某个Ajax请求不缓存, 它的方式就是设置{cache: false},最终它便会在生成的URL中加上一个临时参数,以保证后面的请求的地址是不重复的, 最终达到避开缓存的目的。JQuery的使用太简单,我就不再给出示例代码了。

时间: 2025-01-13 21:01:47

asp.net页面的304 Not Modified代码与 原理的相关文章

宏观视角下的浏览器:05 | 渲染流程(上):HTML、CSS和JavaScript,是如何变成页面的?

前言:该篇说明:请见 说明 —— 浏览器工作原理与实践 目录 在上一篇文章中我们介绍了导航相关的流程,那导航被提交后又会怎么样呢?就进入了渲染阶段.这个阶段很重要,了解其相关流程能让你 “看透” 页面是如何工作的,有了这些知识,你可以解决一系列相关的问题,比如能熟练使用开发者工具,因为能够理解开发者工具里面大部分项目的含义,能优化页面卡顿问题,使用 JavaScript 优化动画流程,通过优化样式表来防止强制同步布局,等等. 既然它的功能这么强大,那么今天,我们就来好好聊聊 渲染流程. 通常,我

5秒后跳转到另一个页面的js代码

今天看视频学习时学习了一种新技术,即平时我们在一个页面点击"提交"或"确认"会自动跳转到一个页面. 在网上搜了一下,关于这个技术处理有多种方法,我只记下我在视频里学到的三种: 1.用一个response.sendRedirect("目标页面.jsp\.htm");实现直接跳转: 2.有时我们需要有点提示,比如"x秒后自动跳转,若没有跳转,请点击此处",则可以在myeclipse中调用Snippets中的Delay Go To

asp.net 使用HttpModule对全站输出的动态页面的HTML内容进行修改,不会错乱

比上一编<asp.net 使用页适配器和重写Render对全站输出的页面的HTML内容进行修改,不会错乱>更容易的方方 http://blog.csdn.net/lrxin/article/details/40861039 配置方法: <httpModules> <add name="FileEditModule" type="Framework.FileEditModule, Framework" /> </httpMod

ASP.NET 页生命周期概述

ASP.NET 页运行时,此页将经历一个生命周期,在生命周期中将执行一系列处理步骤.这些步骤包括初始化.实例化控件.还原和维护状态.运行事件处理程序代码以及进行呈现.了解页生命周期非常重要,因为这样做您就能在生命周期的合适阶段编写代码,以达到预期效果.此外,如果您要开发自定义控件,就必须熟悉页生命周期,以便正确进行控件初始化,使用视图状态数据填充控件属性以及运行任何控件行为代码.(控件的生命周期基于页的生命周期,但是页引发的控件事件比单独的 ASP.NET 页中可用的事件多.) 常规页生命周期阶

通过Web Api 和 Angular.js 构建单页面的web 程序

在传统的web 应用程序中,浏览器端通过向服务器端发送请求,然后服务器端根据这个请求发送HTML到浏览器,这个响应将会影响整个的页面,比如说:用户通过一个连接导航到一个页面,会发送一个请求到服务器端,接下来服务器将会发送一个新的页面给浏览器. 但是在单页面应用程序中,整个页面只是在浏览器一开始请求的时候才会加载,接下来的请求,下来的交互请求都是通过ajax 来完成的,这就意味着只有部分的页面会更新,并不需要去加载整个的页面,这就减少了对用户操作的响应时间,从而使用户有一个更流畅的体验.但是在传统

ASP.NET 页生命周期概述1

ASP.NET 页运行时,此页将经历一个生命周期,在生命周期中将执行一系列处理步骤.这些步骤包括初始化.实例化控件.还原和维护状态.运行事件处理程序代码以及进行 呈现.了解页生命周期非常重要,因为这样做您就能在生命周期的合适阶段编写代码,以达到预期效果.此外,如果您要开发自定义控件,就必须熟悉页生命周期, 以便正确进行控件初始化,使用视图状态数据填充控件属性以及运行任何控件行为代码.(控件的生命周期基于页的生命周期,但是页引发的控件事件比单独的 ASP.NET 页中可用的事件多.) 常规页生命周

304 Not Modified

今天在用chrome浏览淘宝页面的时候,发现很多来自淘宝图片HTTP状态码是 304 Not Modified 到百度搜索了一下,明白了 304状态的含义(以下绿色内容来自网络): 304 Not Modified:客户端有缓冲的文件并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档).服务器告诉客户,原来缓冲的文档还可以继续使用. 如果客户端在请求一个文件的时候,发现自己缓存的文件有 Last Modified ,那么在请求中会包含 If

点击按钮(或超链接)如何跳转到另外一个页面并执行目标页面的js函数

页面跳转同时执行js代码$(function(){});url参数传递 标题的前半部分其实不必赘述,按钮也可以换成超链接.. 假设是需要在A页面上的一个按钮,点击后跳转到B页面,传一些参数后且并B页面的某个js函数可以执行~~ 关键在于如何跳转到目标页面之后并「接着」执行「目标页面的js函数」.原因是目标页面的某个js函数原来是需要点击该页面的按钮或超链接才能触发的,但现在需要在跳转到B页面后立即执行! 先不想是从A页面跳转到B页面,假设你想在B页面一打开就执行的话,是需要把代码逻辑写在$(fu

Form提交是会刷新页面的

今天发现如果页面中有form,点击提交按钮是会刷新页面的,为了禁止页面刷新行为,可以这么做: <form class="form-horizontal" id="user" role="form" onsubmit="submitUser(event)"> ...... </form> script // function submitUser(event){ //创建用户 event.preventD