静态文件(如 HTML、CSS、图像和 JavaScript)等是Web程序的重要组成部分。传统的ASP.NET项目一般都是部署在IIS上,IIS是一个功能非常强大的服务器平台,可以直接处理接收到的静态文件处理而不需要经过应用程序池处理,所以很多情况下对于静态文件的处理程序本身是无感知的。ASP.NET Core则不同,作为Server的Kestrel服务是宿主到程序上的,由宿主运行程序启动Server然后可以监听请求,所以通过程序我们直接可以处理静态文件相关。静态文件默认存储到项目的wwwroot目录中,当然我们也可以自定义任意目录去处理静态文件。总之,在ASP.NET Core我们可以处理静态文件相关的请求。
StaticFile三剑客通常我们在说道静态文件相关的时候会涉及到三个话题分别是启用静态文件、默认静态页面、静态文件目录浏览,在ASP.NET Core分别是通过UseStaticFiles、UseDefaultFiles、UseDirectoryBrowser三个中间件去处理。只有配置了相关中间件才能去操作对应的处理,相信大家对这种操作已经很熟了。静态文件操作相关的源码都位于GitHub aspnetcore仓库中的https://github.com/dotnet/aspnetcore/tree/v3.1.6/src/Middleware/StaticFiles/src目录。接下来我们分别探究这三个中间件的相关代码,来揭开静态文件处理的神秘面纱。
UseStaticFilesUseStaticFiles中间件使我们处理静态文件时最常使用的中间件,因为只有开启了这个中间件我们才能使用静态文件,比如在使用MVC开发的时候需要私用js css html等文件都需要用到它,使用的方式也比较简单
//使用默认路径,即wwwroot app.UseStaticFiles(); //或自定义读取路径 var fileProvider = new PhysicalFileProvider($"{env.ContentRootPath}/staticfiles"); app.UseStaticFiles(new StaticFileOptions { RequestPath="/staticfiles", FileProvider = fileProvider });我们直接找到中间件的注册类StaticFileExtensions[点击查看StaticFileExtensions源码]
public static class StaticFileExtensions { public static IApplicationBuilder UseStaticFiles(this IApplicationBuilder app) { return app.UseMiddleware<StaticFileMiddleware>(); } public static IApplicationBuilder UseStaticFiles(this IApplicationBuilder app, string requestPath) { return app.UseStaticFiles(new StaticFileOptions { RequestPath = new PathString(requestPath) }); } public static IApplicationBuilder UseStaticFiles(this IApplicationBuilder app, StaticFileOptions options) { return app.UseMiddleware<StaticFileMiddleware>(Options.Create(options)); } }一般我们最常用到的是无参的方式和传递自定义StaticFileOptions的方式比较多,StaticFileOptions是自定义使用静态文件时的配置信息类,接下来我们大致看一下具体包含哪些配置项[点击查看StaticFileOptions源码]
public class StaticFileOptions : SharedOptionsBase { public StaticFileOptions() : this(new SharedOptions()) { } public StaticFileOptions(SharedOptions sharedOptions) : base(sharedOptions) { OnPrepareResponse = _ => { }; } /// <summary> /// 文件类型提供程序,也就是我们常用的文件名对应MimeType的对应关系 /// </summary> public IContentTypeProvider ContentTypeProvider { get; set; } /// <summary> /// 设置该路径下默认文件输出类型 /// </summary> public string DefaultContentType { get; set; } public bool ServeUnknownFileTypes { get; set; } /// <summary> /// 文件压缩方式 /// </summary> public HttpsCompressionMode HttpsCompression { get; set; } = HttpsCompressionMode.Compress; /// <summary> /// 准备输出之前可以做一些自定义操作 /// </summary> public Action<StaticFileResponseContext> OnPrepareResponse { get; set; } } public abstract class SharedOptionsBase { protected SharedOptionsBase(SharedOptions sharedOptions) { SharedOptions = sharedOptions; } protected SharedOptions SharedOptions { get; private set; } /// <summary> /// 请求路径 /// </summary> public PathString RequestPath { get { return SharedOptions.RequestPath; } set { SharedOptions.RequestPath = value; } } /// <summary> /// 文件提供程序,在.NET Core中如果需要访问文件相关操作可使用FileProvider文件提供程序获取文件相关信息 /// </summary> public IFileProvider FileProvider { get { return SharedOptions.FileProvider; } set { SharedOptions.FileProvider = value; } } }我们自定义静态文件访问时,最常用到的就是RequestPath和FileProvider,一个设置请求路径信息,一个设置读取文件信息。如果需要自定义MimeType映射关系可通过ContentTypeProvider自定义设置映射关系
var provider = new FileExtensionContentTypeProvider(); provider.Mappings[".myapp"] = "application/x-msdownload"; provider.Mappings[".htm3"] = "text/html"; app.UseStaticFiles(new StaticFileOptions { ContentTypeProvider = provider, //可以在输出之前设置输出相关 OnPrepareResponse = ctx => { ctx.Context.Response.Headers.Append("Cache-Control", $"public, max-age=3600"); } });