在Web开发中,如js脚本、css样式、图片等的静态文件通常占据了很大一部分。ASP.NET Core提供了三个中间件来处理这种针对静态文件的请求。利用它们我们不经可以将物理文件发布为通过http请求可以去获取的外部资源。还可以将所在的物理结构也给呈现出来。通过http请求获取的外部资源大部分都来源于存储在服务器磁盘上的静态文件。
对于ASP.NET Core来说,如果静态文件存储在约定的目录下,那么绝大部分文件类型都是可以通过web的形式对外发布的。
像这种在web根目录下的所有文件都会自动的发布为web资源,客户端是可以访问相应的url来读取这些文件的。我们针对某个静态文件的请求其实是通过一个静态文件中间件StaticFiles来处理的。
StaticFiles
示例:
public class demo09
{
public static void Run()
{
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder => builder
.Configure(app => app
.UseStaticFiles()))
.Build()
.Run();
}
}
如果需要发布的静态文件中间件不在web根目录,而是在其它文件夹下呢。
如图,我们在项目下有一个为content的文件夹。
ASP.NET Core在大部分情况下都是利用文件提供对象FileProvider(抽象文件系统)来提供功能的。通过StaticFiles这个方法注册的中间件它的内部就维护着一个FileProvider以及和这个请求路径的映射关系。如果我们调用StaticFiles这个方法,我们没有指定参数,那么这个映射关系的请求路径默认就是web根目录,也就是基地址。我们可以根据显示定义这种映射关系。
示例:
public class demo08
{
public static void Run()
{
var path = Path.Combine(Directory.GetCurrentDirectory(),"content");
// 静态文件中间件配置
var options = new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(path),
RequestPath = "/content"
};
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder => builder
.Configure(app => app
// 静态文件中间件
.UseStaticFiles()
.UseStaticFiles(options)))
.Build()
.Run();
}
}
DirectoryBrowser
在浏览器中访问一个目录。
示例:
public class demo10
{
public static void Run()
{
var path = Path.Combine(Directory.GetCurrentDirectory(),"content");
var fileProvider = new PhysicalFileProvider(path);
var staticFileOptions = new StaticFileOptions
{
FileProvider = fileProvider,
RequestPath = "/content"
};
var directoryBrowserOptions = new DirectoryBrowserOptions
{
FileProvider = fileProvider,
RequestPath = "/content"
};
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder => builder
.Configure(app => app
// 目录中间件
.UseStaticFiles()
.UseStaticFiles(staticFileOptions)
.UseDirectoryBrowser()
.UseDirectoryBrowser(directoryBrowserOptions)))
.Build()
.Run();
}
}
DefaultFiles
设置默认页面。
示例:
public class demo11
{
public static void Run()
{
var path = Path.Combine(Directory.GetCurrentDirectory(),"content");
var fileProvider = new PhysicalFileProvider(path);
var staticFileOptions = new StaticFileOptions
{
FileProvider = fileProvider,
RequestPath = "/content"
};
var directoryBrowserOptions = new DirectoryBrowserOptions
{
FileProvider = fileProvider,
RequestPath = "/content"
};
// 默认页面中间件配置
var defaultFilesOptions = new DefaultFilesOptions
{
FileProvider = fileProvider,
RequestPath = "/content"
};
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder => builder
.Configure(app => app
// 默认页面中间件
.UseDefaultFiles()
.UseDefaultFiles(defaultFilesOptions)
.UseStaticFiles()
.UseStaticFiles(staticFileOptions)
.UseDirectoryBrowser()
.UseDirectoryBrowser(directoryBrowserOptions)))
.Build()
.Run();
}
}
DefaultFiles必须在StaticFiles和DirectoryBrowser之前。否则DefaultFiles无法发挥作用。
- DefaultFiles和DirectoryBrowser的处理都是针对目录的请求。如果先注册DirectoryBrowser页面总是会先显示目录的结构。如果先注册DefaultFiles页面会在默认页面不存在的情况下,才传递到DirectoryBrowser继续处理,再将目录结构呈现出来。
- DefaultFiles是采用URL重写的方式实现的。也就是说DefaultFiles会针对目录的请求改写成针对默认页面的请求。而最终对默认页面的请求还需要依赖StaticFiles来实现。
- DefaultFiles在默认的情况下总是以约定好的名称在当前的请求目录下去寻找默认页面,如果说作为默认页面的文件没有采用约定命名。则需要在DefaultFilesOptions添加DefaultFileNames。
FileExtensionContentTypeProvider
我们知道http请求要想文件能在浏览器正常显示基本前提就是响应报文通过响应头content-type必须与内容是一致的。假设说你从服务器上获取到的为image/jpg而响应报文中content-type返回的为txt。这种是无法在浏览器正常显示的。
ASP.NET Core针对媒体类型的解析是通过一个内部对象完成的。这个内部对象定义了数百种常用文件扩展名对应的媒体类型之间的映射关系。
源码位置:\aspnetcore\src\Middleware\StaticFiles\src\FileExtensionContentTypeProvider.cs
源码:
/// <summary>
/// Provides a mapping between file extensions and MIME types.
/// </summary>
public class FileExtensionContentTypeProvider : IContentTypeProvider
{
// Notes:
// - This table was initially copied from IIS and has many legacy entries we will maintain for backwards compatibility.
// - We only plan to add new entries where we expect them to be applicable to a majority of developers such as being
// used in the project templates.
#region Extension mapping table
/// <summary>
/// Creates a new provider with a set of default mappings.
/// </summary>
public FileExtensionContentTypeProvider()
: this(new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ ".323", "text/h323" },
{ ".3g2", "video/3gpp2" },
{ ".3gp2", "video/3gpp2" },
{ ".3gp", "video/3gpp" },
{ ".3gpp", "video/3gpp" },
{ ".aac", "audio/aac" },
{ ".aaf", "application/octet-stream" },
{ ".aca", "application/octet-stream" },