你的位置:首页 > 软件开发 > ASP.net > ASP.NET Core应用针对静态文件请求的处理[1]: 以Web的形式发布静态文件

ASP.NET Core应用针对静态文件请求的处理[1]: 以Web的形式发布静态文件

发布时间:2016-12-08 09:00:24
虽然ASP.NET Core是一款“动态”的Web服务端框架,但是在很多情况下都需要处理针对静态文件的请求,最为常见的就是这对JavaScript脚本文件、CSS样式文件和图片文件的请求。针对不同格式的静态文件请求的处理,ASP.NET Core为我们提供了三个中间件,它们将是本 ...

ASP.NET Core应用针对静态文件请求的处理[1]: 以Web的形式发布静态文件

虽然get='_blank'>ASP.NET Core是一款“动态”的Web服务端框架,但是在很多情况下都需要处理针对静态文件的请求,最为常见的就是这对JavaScript脚本文件、CSS样式文件和图片文件的请求。针对不同格式的静态文件请求的处理,ASP.NET Core为我们提供了三个中间件,它们将是本系列文章论述的重点。不过在针对对它们展开介绍之前,我们照理通过一些简单的实例来体验一下如何在一个ASP.NET Core应用中发布静态文件。[本文已经同步到《ASP.NET Core框架揭秘》之中]

目录

除了注册必需的StaticFileMiddleware中间件之外,我们还调用了WebHostBuilder的UseContentRoot方法将当前项目的根目录作为ContentRoot目录。我们知道ASP.NET Core应用具有两个重要的根目录,它们分别是ContentRoot和WebRoot,后者也是对外发布的静态文件默认使用的根目录。由于WebRoot目录的默认路径就是“{contentroot}/wwwroot”,所示上面这段程序就是将项目中的这个wwwroot目录下的所有静态文件发布出来。

当这个程序运行之后,我们就可以通过向对应URL发送HTTP请求的方式来获取某个的文件,这个URL由文件相当于wwwroot目录的路径来决定。比如JPG文件“~/wwwroot/img/dophin1.jpg”对应的URL为“http://

按照上面这段程序指定的映射关系,对于存储在“~/doc/”目录下的这个PDF文件(“checklist.pdf”),发布在Web上的URL为“http://localhost:5000/documents/checklist.pdf”。当我们在浏览器上请求这个地址时,该PDF文件的内容将会按照如下图所示的形式显示在浏览器上。

ASP.NET Core应用针对静态文件请求的处理[1]: 以Web的形式发布静态文件

二、浏览目录内容

注册的StaticFileMiddleware中间件只会处理针对某个具体静态文件的额请求,如果我们向针对某个目录的URL发送HTTP请求(比如“http://localhost:5000/img/”),得到的将是一个状态为404的响应。不过我们可以通过注册另一个名为DirectoryBrowserMiddleware的中间件来显示请求目录的内容。具体来说,这个中间件会返回一个HTML页面,请求目录下的所有文件将以表格的形式包含在这个页面中。对于我们演示的这个应用来说,我们可以按照如下的方式调用UseDirectoryBrowser方法来注册这个DirectoryBrowserMiddleware中间件。

  1: public class Program
  2: {
  3:   public static void Main()
  4:   {
  5:     string contentRoot = Directory.GetCurrentDirectory();
  6:     IFileProvider fileProvider = new PhysicalFileProvider(
  7:       Path.Combine(contentRoot, "doc"));
  8:     new WebHostBuilder()
  9:       .UseContentRoot(contentRoot)
 10:       .UseKestrel()
 11:       .Configure(app => app
 12:         .UseStaticFiles()
 13:         .UseStaticFiles(new StaticFileOptions {
 14:           FileProvider = fileProvider,
 15:           RequestPath = "/documents"
 16:         })
 17:         .UseDirectoryBrowser()
 18:         .UseDirectoryBrowser(new DirectoryBrowserOptions {
 19:             FileProvider = fileProvider,
 20:             RequestPath = "/documents"
 21:         }))
 22:       .Build()
 23:       .Run();
 24:   }
 25: }

当上面这个应用启动之后,如果我们利用浏览器向针对某个目录的URL(比如“http://localhost:5000/”或者“http://localhost:5000/img/”),目标目录的内容(包括子目录和文件)将会以下图所示的形式显示在一个表格中。不仅仅如此,子目录和文件均会显示为链接,指向目标目录或者文件的URL。

ASP.NET Core应用针对静态文件请求的处理[1]: 以Web的形式发布静态文件

三、显示默认页面

从安全的角度来讲,利用注册的UseDirectoryBrowser中间件显示一个目录浏览页面会将整个目标目录的接口和所有文件全部暴露出来,所以这个中间件需要根据自身的安全策略谨慎使用。对于针对目录的请求,另一种更为常用的响应策略就是显示一个保存在这个目录下的默认页面。按照约定,作为默认页面的文件一般采用如下四种命名方式:default.htm、default.html、index.htm或者index.html。针对目标目录下默认页面的呈现实现在一个名为DefaultFilesMiddleware的中间件中,我们演示的这个应用可以按照如下的方式调用UseDefaultFiles方法来注册这个中间件。

  1: public class Program
  2: {
  3:   public static void Main()
  4:   {
  5:     string contentRoot = Directory.GetCurrentDirectory();
  6:     IFileProvider fileProvider = new PhysicalFileProvider(Path.Combine(contentRoot, "doc"));
  7:  
  8:     new WebHostBuilder()
  9:       .UseContentRoot(contentRoot)
 10:       .UseKestrel()
 11:       .Configure(app => app
 12:         .UseDefaultFiles()
 13:         .UseDefaultFiles(new DefaultFilesOptions{
 14:           RequestPath = "/documents",
 15:           FileProvider = fileProvider,
 16:         })
 17:         .UseStaticFiles()
 18:         .UseStaticFiles(new StaticFileOptions
 19:         {
 20:           FileProvider = fileProvider,
 21:           RequestPath = "/documents"
 22:         })
 23:         .UseDirectoryBrowser()
 24:         .UseDirectoryBrowser(new DirectoryBrowserOptions
 25:         {
 26:           FileProvider = fileProvider,
 27:           RequestPath = "/documents"
 28:         }))
 29:       .Build()
 30:       .Run();
 31:   }
 32: }

现在我们在“~/wwwroot/img/”目录下创建一个名为index.htm的默认页面,现在利用浏览器访问这个目录对应的URL(“http://localhost:5000/img/”),显示就时这个页面的内容。

ASP.NET Core应用针对静态文件请求的处理[1]: 以Web的形式发布静态文件

我们必须在注册StaticFileMiddleware和DirectoryBrowserMiddleware之前注册DefaultFilesMiddleware,否则它起不了任何作用。由于DirectoryBrowserMiddleware和DefaultFilesMiddleware这两个中间件处理的均是针对目录的请求,如果DirectoryBrowserMiddleware先被注册,那么显示的总是目录的内容。若DefaultFilesMiddleware先被注册,在默认页面不存在情况下回显示目录的内容。至于为什么要先于StaticFileMiddleware之前注册DefaultFilesMiddleware,则是因为后者是通过采用URL重写的方式实现的,也就是说这个中间件会将针对目录的请求改写成针对默认页面的请求,而最终针对默认页面的请求还得依赖StaticFileMiddleware完成。

DefaultFilesMiddleware中间件在默认情况下总是以约定的名称(default.htm、default.html、index.htm或者index.html)在当前请求的目录下定位默认页面。如果我们希望作为默认页面的文件不能按照这样的约定命名(比如readme.htm),我们需要按照如下的方式显式指定默认页面的文件名。

  1: public class Program
  2: {
  3:   public static void Main()
  4:   {
  5:     string contentRoot = Directory.GetCurrentDirectory();
  6:     IFileProvider fileProvider = new PhysicalFileProvider(Path.Combine(contentRoot, "doc"));
  7:  
  8:     DefaultFilesOptions options1 = new DefaultFilesOptions();
  9:     DefaultFilesOptions options2 = new DefaultFilesOptions{
 10:       RequestPath = "/documents",
 11:       FileProvider = fileProvider
 12:     };
 13:     options1.DefaultFileNames.Add("readme.htm");
 14:     options2.DefaultFileNames.Add("readme.htm");
 15:  
 16:     new WebHostBuilder()
 17:       .UseContentRoot(contentRoot)
 18:       .UseKestrel()
 19:       .Configure(app => app
 20:         .UseDefaultFiles(options1)
 21:         .UseDefaultFiles(options2)
 22:         .UseStaticFiles()
 23:         .UseStaticFiles(new StaticFileOptions{
 24:           FileProvider = fileProvider,
 25:           RequestPath = "/documents"
 26:         })
 27:         .UseDirectoryBrowser()
 28:         .UseDirectoryBrowser(new DirectoryBrowserOptions{
 29:           FileProvider = fileProvider,
 30:           RequestPath = "/documents"
 31:         }))
 32:     .Build()
 33:     .Run();
 34:   }
 35: }

四、映射媒体类型

通过上面演示的实例可以看出,浏览器能够正确的将请求的目标文件的内容正常的呈现出来。对HTTP协议具有基本了解的人都应该知道,响应的文件能够在支持的浏览器上呈现具有一个基本的前提,那就是响应消息通过Content-Type报头携带的媒体类型必须与内容一致。我们的实例演示了针对两种类型文件的请求,一种是JPG文件,另一种是PDF文件,对应的媒体类型分别是“image/jpg”和“application/pdf”,那么StaticFileMiddleware是如何正确解析出正确的媒体类型的呢?

StaticFileMiddleware针对媒体类型的解析是通过一个名为ContentTypeProvider的对象来实现的,而默认使用的则是一个FileExtensionContentTypeProvider对象。顾名思义,FileExtensionContentTypeProvider是根据文件的扩展命名来解析媒体类型的。FileExtensionContentTypeProvider内部预定了数百种常用文件扩展名与对应媒体类型之间的映射关系,所以如果我们发布的静态文件具有标准的扩展名,StaticFileMiddleware就能为对应的响应赋予正确的媒体类型。

那么如果某个文件的扩展名没有在这个预定义的映射之中,或者我们需要某个预定义的扩展名匹配不同的媒体类型,我们应该如何解决呢?还是针对我们演示的这个实例,想在我将“~/wwwroot/img/ dophin1.jpg”这个文件的扩展名改成“.img”,毫无疑问StaticFileMiddleware将能为针对该文件的请求解析出正确媒体类型。这个问题具有若干不同的解决方案,第一种方案就是让StaticFileMiddleware支持不能识别的文件类型,并为它们设置一个默认的媒体类型,如下所示了具体采用的编程方式。

  1: public class Program
  2: {
  3:   public static void Main()
  4:   { 
  5:     new WebHostBuilder()
  6:       .UseContentRoot(Directory.GetCurrentDirectory();)
  7:       .UseKestrel()
  8:       .Configure(app => app.UseStaticFiles(new StaticFileOptions {
  9:         ServeUnknownFileTypes = true,
 10:         DefaultContentType   = "image/jpg"
 11:       }))
 12:       .Build()
 13:       .Run();
 14:   }
 15: }

上述这种解决方案只能设置一种默认媒体类型,如果具有多种需要映射成不同媒体类型的非识别文件类型,采用这种方案就无能为力了,所以最根本的解决方案还是需要将不能识别的文件类型和对应的媒体类型进行映射。由于StaticFileMiddleware使用的ContentTypeProvider是可以定制的,我们可以按照如下的方式显式地为StaticFileMiddleware指定一个FileExtensionContentTypeProvider对象作为它的ContentTypeProvider,然后将取缺失的映射添加到这个FileExtensionContentTypeProvider对象上。

  1: public class Program
  2: {
  3:   public static void Main()
  4:   {
  5:     FileExtensionContentTypeProvider contentTypeProvider = new FileExtensionContentTypeProvider();
  6:     contentTypeProvider.Mappings.Add(".img", "image/jpg");
  7:  
  8:     new WebHostBuilder()
  9:       .UseContentRoot(Directory.GetCurrentDirectory())
 10:       .UseKestrel()
 11:       .Configure(app => app.UseStaticFiles(new StaticFileOptions{
 12:         ContentTypeProvider = contentTypeProvider
 13:       }))
 14:       .Build()
 15:       .Run();
 16:   }
 17: }

 


ASP.NET Core应用针对静态文件请求的处理[1]: 以Web的形式发布静态文件

原标题:ASP.NET Core应用针对静态文件请求的处理[1]: 以Web的形式发布静态文件

关键词:ASP.NET

*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。