细说ASP.NET Core静态文件的缓存方式
一、前言
我们在优化Web服务的时候,对于静态的资源文件,通常都是通过客户端缓存、服务器缓存、CDN缓存,这三种方式来缓解客户端对于Web服务器的连接请求压力的。
本文指在这三个方面,在ASP.NET Core中静态文件的实现过程和使用方法进行阐述。当然也可以考虑使用反向代理的方式(例如IIS或Nginx),这些不是本文讨论的内容。
本文重点展示如何通过StaticFileMiddleware中间件,提高网站的性能。虽然这不是唯一缓存文件的方式,我们还可以通过ResponseCacheAttribute特性为ASP.NET Core Mvc的Controller和Action进行缓存的设置。
二、StaticFileMiddleware
1.文件服务与默认缓存规则
当创建一个ASP.NET Core的项目时,查看Startup.Configure方法,就会看到默认模板生成的添加StaticFileMiddleware中间件的方法。
public void Configure(IApplicationBuilder app)
{
// looging and exception handler removed for clarity app.UseStaticFiles(); app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
这样就使你的应用程序能够处理,程序目录下wwwroot目录的静态文件内容。在我们添加文件缓存之前,我们先要看一下StaticFileMiddleware默认的策略是怎么样的。当第一次加载程序时,浏览器将打开页面并下载所有的资源连接。假如页面没有错误返回都是正确那么就是返回文件数据和Http Status为200 -OK的状态。

然后我们看下这个Http请求对应的Response Header,这里会包含ETag和Last-Modified两个值。HTTP内容如下:
HTTP/1.1 OK
Date: Sat, Oct :: GMT
Content-Type: image/svg+xml
Last-Modified: Sat, Oct :: GMT
Accept-Ranges: bytes
ETag: "1d226ea1f827703"
Server: Kestrel
如果再次请求这个地址的话,浏览器将发送ETag和Last-Modified的值到服务端,如果两个值没有变化,那么服务端会发送状态到浏览器,那么浏览器将使用之前的资源而不是重新下载一份。

这样就提高了,浏览器的响应性能,因为文件都缓存到了客户端,并且通过304状态,服务端与浏览器的请求流量得以减少。
2.设置文件缓存时间
当然我们都知道如果要设置某一请求的缓存,只需要设置Header为Cache-Control的值。那么在StaticFileMiddleware中间件中,我们怎么设置这个Header呢?
using Microsoft.Net.Http.Headers; app.UseStaticFiles(new StaticFileOptions
{
OnPrepareResponse = ctx =>
{
const int durationInSeconds = * * ;
ctx.Context.Response.Headers[HeaderNames.CacheControl] =
"public,max-age=" + durationInSeconds;
}
});
设置后每一个静态文件的请求都会执行这个方法,包括200和304状态的请求;而且在这个例子里浏览器会自动缓存这些文件24小时,但是在此期间并不会返回404状态。
一旦max-age设置的时间过期,浏览器就不会再使用本地缓存,而去直接请求服务器端。这样已经避免了一些额外的请求到服务器端了。如果我们在浏览器与服务器中间使用CDN缓存文件数据的话,这样就算客户端浏览器的缓存过期了,但是请求也不会到我们的服务器上,而是请求到CDN缓存服务器。
下面我们看看文件缓存在ASP.NET Core中是如何判断缓存失效的?.NET Core开源的代码为我们提供了了解它的入口【代码 Source Code】。核心代码如下:
_length = _fileInfo.Length;
DateTimeOffset last = _fileInfo.LastModified;
// Truncate to the second.
_lastModified = new DateTimeOffset(last.Year, last.Month, last.Day, last.Hour, last.Minute, last.Second, last.Offset).ToUniversalTime();
long etagHash = _lastModified.ToFileTime() ^ _length;
_etag = new EntityTagHeaderValue('\"' + Convert.ToString(etagHash, ) + '\"');
服务器端如果检测到文件改变就会返回200状态给浏览器,如果没有变化则返回304状态给浏览器端。
不幸的是,一旦我们添加了缓存,浏览器将不再向服务器发出请求。该文件可能已经完全改变或已被完全删除,但如果浏览器不要求,服务器将不能通知浏览器重新发起无缓存的请求!
3.为静态文件提供版本号
通常我们都使用形如https://localhost/js/site.js?v=1 这样的地址来解决缓存的问题。通过给静态文件生成唯一的版本号,做为QueryString进行请求时,服务器将重新输出文件内容。
在ASP.NET Core中Tag Hepers为我们提供了这样的API:
<script src="~/js/site.js" asp-append-version="true"></script>
这段代码最终在浏览器端会被渲染为如下Html代码:
<script src="/js/site.js?v=Ynfdc1vuMNOWZfqTj4N3SPcebazoGXiIPgtfE-b2TO4"></script>
如果静态文件发生改变,Tag Helper就是重新计算文件的哈希值,它采用 SHA256的哈希值。当然以前服务器缓存的文件版本也随之失效了。这个asp-append-version Tag Helper可以支持Img、Script和Link元素。
ASP.NET Core的源代码我们来看看是怎么计算文件变化的:【源代码 Source Code】 。
三、ASP.NET Core与CDN?
我们在使用CDN时,因为还要进行开发任务,一般我们都要有两套地址,一套是CDN上的文件地址,一套是本地调试开发用的地址。ASP.NET Core中也为我们提供了Tag Helper来解决这样的问题。直接上代码实例吧:
<link rel="stylesheet" href="//ajax.aspnetcdn.com/ajax/bootstrap/3.0.0/css/bootstrap.min.css"
asp-fallback-href="~/lib/bootstrap/css/bootstrap.min.css"
asp-fallback-test-class="hidden"
asp-fallback-test-property="visibility"
asp-fallback-test-value="hidden" /> <script src="//ajax.aspnetcdn.com/ajax/bootstrap/3.0.0/bootstrap.min.js"
asp-fallback-src="~/lib/bootstrap/js/bootstrap.min.js"
asp-fallback-test="window.jQuery">
</script>
Tag Helper:asp-fallback-* 解决开发时使用的文件地址问题。 当然它也可以asp-append-version 两个Tag Helper一起使用,这样就实现了,在CDN文件缓存的同步问题。
四、写在最后
新的ASP.NET Core为我们提供了很多现有互联网行业的解决方案,也给.NET开发人员引入了先进思想。
GitHub:https://github.com/maxzhang1985/YOYOFx 如果觉还可以请Star下, 欢迎一起交流。
.NET Core 和 YOYOFx 的交流群: 214741894
细说ASP.NET Core静态文件的缓存方式的更多相关文章
- NET Core静态文件的缓存方式
NET Core静态文件的缓存方式 阅读目录 一.前言 二.StaticFileMiddleware 三.ASP.NET Core与CDN? 四.写在最后 回到目录 一.前言 我们在优化Web服务的时 ...
- [转]NET Core静态文件的缓存方式
本文转自:https://www.cnblogs.com/Leo_wl/p/6059349.html 阅读目录 NET Core静态文件的缓存方式 一.前言 二.StaticFileMiddlewar ...
- ASP.NET Core 静态文件 - ASP.NET Core 基础教程 - 简单教程,简单编程
原文:ASP.NET Core 静态文件 - ASP.NET Core 基础教程 - 简单教程,简单编程 ASP.NET Core 静态文件 前几章节中,我们学习了 ASP.NET Core 的中间件 ...
- ASP.NET Core静态文件中间件[1]: 搭建文件服务器
虽然ASP.NET Core是一款"动态"的Web服务端框架,但是由它接收并处理的大部分是针对静态文件的请求,最常见的是开发Web站点使用的3种静态文件(JavaScript脚本. ...
- ASP.NET Core静态文件处理源码探究
前言 静态文件(如 HTML.CSS.图像和 JavaScript)等是Web程序的重要组成部分.传统的ASP.NET项目一般都是部署在IIS上,IIS是一个功能非常强大的服务器平台,可以直接 ...
- ASP.NET Core 静态文件及JS包管理器(npm, Bower)的使用
在 ASP.NET Core 中添加静态文件 虽然ASP.NET主要大都做着后端的事情,但前端的一些静态文件也是很重要的.在ASP.NET Core中要启用静态文件,需要Microsoft.AspNe ...
- ASP.NET Core 静态文件
静态文件(HTML,CSS,图片和Javascript之类的资源)会被ASP.NET Core应用直接提供给客户端. 静态文件通常位于网站根目录(web root) <content-root& ...
- asp .net core 静态文件资源
前言 对静态资源的简单的一个概况,在<重新整理.net core 计1400篇>系列后面会深入. 正文 我们在加入中间件是这样写的: app.UseStaticFiles(); 默认是给w ...
- ASP.NET Core中的Http缓存
ASP.NET Core中的Http缓存 Http响应缓存可减少客户端或代理对web服务器发出的请求数.响应缓存还减少了web服务器生成响应所需的工作量.响应缓存由Http请求中的header控制. ...
随机推荐
- c#控制打印机杂项
因项目中需要用到控制打印机的相关信息,此贴将网络寻找的资料做了些整理 1. C# 如何设置系统的默认打印机 using System.Runtime.InteropServices; [DllIm ...
- Hadoop学习笔记—13.分布式集群中节点的动态添加与下架
开篇:在本笔记系列的第一篇中,我们介绍了如何搭建伪分布与分布模式的Hadoop集群.现在,我们来了解一下在一个Hadoop分布式集群中,如何动态(不关机且正在运行的情况下)地添加一个Hadoop节点与 ...
- ASP.Net请求处理机制初步探索之旅 - Part 5 ASP.Net MVC请求处理流程
好听的歌 我一直觉得看一篇文章再听一首好听的歌,真是种享受.于是,我在这里嵌入一首好听的歌,当然你觉得不想听的话可以点击停止,歌曲 from 王菲 <梦中人>: --> 开篇:上一篇 ...
- 作业六:团队项目——编写项目的Spec
主要内容: 各组结合所选项目,编写项目的规格说明书(Spec),Spec应至少包含以下内容:(20分) 1. Spec的目标 2. 项目的典型用户和场景 3. 项目的用例模型 4. 项目中涉及到的术语 ...
- SQL Server 执行计划缓存
标签:SQL SERVER/MSSQL SERVER/数据库/DBA/内存池/缓冲区 概述 了解执行计划对数据库性能分析很重要,其中涉及到了语句性能分析与存储,这也是写这篇文章的目的,在了解执行计划之 ...
- 使用GDB调试Go语言
用Go语言已经有一段时间了,总结一下如何用GDB来调试它! ps:网上有很多文章都有描述,但是都不是很全面,这里将那些方法汇总一下 GDB简介 GDB是GNU开源组织发布的⼀一个强⼤大的UNIX下的 ...
- EF:The provider did not return a ProviderManifest instance
报告错误1:指定的存储区提供程序在配置中找不到,或者无效. 报告错误2:System.Data.ProviderIncompatibleException: The provider did not ...
- java spring 邮件发送
开发中经常会遇到发送邮件进行用户验证,或者其它推送信息的情况,本文基于spring,完成邮件的发送,主要支持普通文本邮件的发送,html文本邮件的发送,带附件的邮件发送,没有实现群发.多个附件发送等需 ...
- <canvas>设置宽高遇到的问题
在使用<canvas>元素时必须设置宽度和高度,指定可以绘画的区域大小.但是这里设置宽度和高度的时候有一个小问题. 样例代码: <!DOCTYPE html> <html ...
- MyBatis-Exception:org.apache.ibatis.exceptions.PersistenceException
错误信息如下: HTTP Status 500 - org.mybatis.spring.MyBatisSystemException: nested exception is org.apache. ...