理解ASP.NETCore-⽂件服务器(FileServer)
注:本⽂⾪属于《理解ASP.NET Core》系列⽂章,请查看置顶博客或
提供静态⽂件
静态⽂件默认存放在 Web根⽬录(Web Root) 中,路径为 项⽬根⽬录(Content Root) 下的wwwroot⽂件夹,也就是{Content
Root}/wwwroot。
如果你调⽤了Host.CreateDefaultBuilder⽅法,那么在该⽅法中,会通过UseContentRoot⽅法,将程序当前⼯作⽬录
(Directory.GetCurrentDirectory())设置为项⽬根⽬录。具体可以查看⼀节。
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
当然,你也可以通过UseWebRoot扩展⽅法将默认的路径{Content Root}/wwwroot修改为⾃定义⽬录(不过,你改它⼲啥捏?)
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
// 配置静态资源的根⽬录为 mywwwroot,默认为 wwwroot
webBuilder.UseWebRoot("mywwwroot");
webBuilder.UseStartup<Startup>();
});
为了⽅便,后⾯均使⽤ wwwroot 来表⽰Web根⽬录
⾸先,我们先在 wwwroot ⽂件夹下创建⼀个名为 config.json 的⽂件,内容随便填写
注意,确保 wwwroot 下的⽂件的属性为“如果较新则复制”或“始终复制”。
接着,我们通过UseStaticFiles扩展⽅法,来注册静态⽂件中间件StaticFileMiddleware:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseStaticFiles();
}
如果你的项⽬中启⽤SwaggerUI,那么你会发现,即使你没有⼿动通过调⽤UseStaticFiles()添加中间件,你也可以访问 wwwroot ⽂件下的⽂件,这是因为 SwaggerUIMiddleware 中使⽤了 StaticFileMiddleware
提供Web根⽬录之外的⽂件
上⾯我们已经能够提供 wwwroot ⽂件夹内的静态⽂件了,那如果我们的⽂件不在 wwwroot ⽂件夹内,那如何提供呢?
很简单,我们可以针对StaticFileMiddleware中间件进⾏⼀些额外的配置,了解⼀下配置项:
public abstract class SharedOptionsBase
{
// ⽤于⾃定义静态⽂件的相对请求路径
public PathString RequestPath { get; set; }
// ⽂件提供程序
public IFileProvider FileProvider { get; set; }
// 是否补全路径末尾斜杠“/”,并重定向
public bool RedirectToAppendTrailingSlash { get; set; }
}
public class StaticFileOptions : SharedOptionsBase
{
// ContentType提供程序
public IContentTypeProvider ContentTypeProvider { get; set; }
// 如果 ContentTypeProvider ⽆法识别⽂件类型,是否仍作为默认⽂件类型提供
public bool ServeUnknownFileTypes { get; set; }
// 当 ServeUnknownFileTypes = true 时,若出现⽆法识别的⽂件类型,则将该属性的值作为此⽂件的类型
// 当 ServeUnknownFileTypes = true 时,必须赋值该属性,才会⽣效
public string DefaultContentType { get; set; }
// 当注册了HTTP响应压缩中间件时,是否对⽂件进⾏压缩
public HttpsCompressionMode HttpsCompression { get; set; } = HttpsCompressionMode.Compress;
// 在HTTP响应的 Status Code 和 Headers 设置完毕之后,Body 写⼊之前进⾏调⽤
// ⽤于添加或更改 Headers
public Action<StaticFileResponseContext> OnPrepareResponse { get; set; }
}
假设我们现在有这样⼀个⽂件⽬录结构:
wwwroot
config.json
files
file.json
然后,除了⽤于提供 wwwroot 静态⽂件的中间件外,我们还要注册⼀个⽤于提供 files 静态⽂件的中间件:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// 提供 wwwroot 静态⽂件
app.UseStaticFiles();
// 提供 files 静态⽂件
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "files")),
// 指定⽂件的访问路径,允许与 FileProvider 中的⽂件夹不同名
// 如果不指定,则可通过 localhost:5000/file.json 获取,
// 如果指定,则需要通过 localhost:5000/files/file.json 获取
RequestPath = "/files",
OnPrepareResponse = ctx =>
{
// 配置前端缓存 600s(为了后续⽰例的良好运⾏,建议先不要配置该Header)
ctx.Context.Response.Headers.Add(HeaderNames.CacheControl, "public,max-age=600");
}
});
}
建议将公开访问的⽂件放置到 wwwroot ⽬录下,⽽将需要授权访问的⽂件放置到其他⽬录下(在调⽤UseAuthorization之后调⽤UseStaticFiles并指定⽂件⽬录)
提供⽬录浏览
上⾯,我们可以通过Url访问某⼀个⽂件的内容,⽽通过UseDirectoryBrowser,注册DirectoryBrowserMiddleware中间件,可以让我们在浏览器中以⽬录的形式来访问⽂件列表。
另外,DirectoryBrowserMiddleware中间件的可配置项除了SharedOptionsBase中的之外,还有⼀个Formatter,⽤于⾃定义⽬录视图。
public class DirectoryBrowserOptions : SharedOptionsBase
{
public IDirectoryFormatter Formatter { get; set; }
}
⽰例如下:
public void ConfigureServices(IServiceCollection services)
{
services.AddDirectoryBrowser();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
asp查看源码配置ui{
// 通过 localhost:5000,即可访问 wwwroot ⽬录
app.UseDirectoryBrowser();
// 通过 localhost:5000/files,即可访问 files ⽬录
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
// 如果指定了没有在 UseStaticFiles 中提供的⽂件⽬录,虽然可以浏览⽂件列表,但是⽆法访问⽂件内容
FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "files")),
// 这⾥⼀定要和 StaticFileOptions 中的 RequestPath ⼀致,否则会⽆法访问⽂件
RequestPath = "/files"
});
}
提供默认页
通过UseDefaultFiles,注册DefaultFilesMiddleware中间件,允许在访问静态⽂件、但未提供⽂件名的情况下(即传⼊的是⼀个⽬录的路径),提供默认页的展⽰。
注意:UseDefaultFiles必须在UseStaticFiles之前进⾏调⽤。因为DefaultFilesMiddleware仅仅负责重写Url,实际上默认页⽂件,仍然是通
过StaticFilesMiddleware来提供的。
默认情况下,该中间件会按照顺序搜索⽂件⽬录下的HTML页⾯⽂件:
default.htm
default.html
index.htm
index.html
另外,DefaultFilesMiddleware中间件的可配置项除了SharedOptionsBase中的之外,还有⼀个DefaultFileNames,是个列表,⽤于⾃定义默认页的⽂件名,⾥⾯的默认值就是上⾯提到的4个⽂件名。
public class DefaultFilesOptions : SharedOptionsBase
{
public IList<string> DefaultFileNames { get; set; }
}
⽰例如下:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// 会去 wwwroot 寻 default.htm 、default.html 、index.htm 或 index.html ⽂件作为默认页
app.UseDefaultFiles();
// 设置 files ⽬录的默认页
var defaultFilesOptions = new DefaultFilesOptions();
defaultFilesOptions.DefaultFileNames.Clear();
// 指定默认页名称
defaultFilesOptions.DefaultFileNames.Add("index1.html");
// 指定请求路径
defaultFilesOptions.RequestPath = "/files";
// 指定默认页所在的⽬录
defaultFilesOptions.FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "files"));
app.UseDefaultFiles(defaultFilesOptions);
}
UseFileServer
UseFileServer集成了UseStaticFiles、UseDefaultFiles和UseDirectoryBrowser的功能,⽤起来⽅便⼀些,也是我们项⽬中使⽤的⾸选扩展⽅法。先看⼀下FileServerOptions:
public class FileServerOptions : SharedOptionsBase
{
public FileServerOptions()
: base(new SharedOptions())
{
StaticFileOptions = new StaticFileOptions(SharedOptions);
DirectoryBrowserOptions = new DirectoryBrowserOptions(SharedOptions);
DefaultFilesOptions = new DefaultFilesOptions(SharedOptions);
EnableDefaultFiles = true;
}
public StaticFileOptions StaticFileOptions { get; private set; }
public DirectoryBrowserOptions DirectoryBrowserOptions { get; private set; }
public DefaultFilesOptions DefaultFilesOptions { get; private set; }
// 默认禁⽤⽬录浏览
public bool EnableDirectoryBrowsing { get; set; }
// 默认启⽤默认页(在构造函数中初始化的)
public bool EnableDefaultFiles { get; set; }
}
可以看到,FileServerOptions包含了StaticFileOptions、DirectoryBrowserOptions和DefaultFilesOptions三个选项,可以针
对StaticFileMiddleware、DirectoryBrowserMiddleware和DefaultFilesMiddleware进⾏⾃定义配置。另外,其默认启⽤了静态⽂件和默认页,禁⽤了⽬录浏览。
下⾯举个例⼦熟悉⼀下:
假设⽂件⽬录:
files
images
1.jpg
file.json
myindex.html
public void ConfigureServices(IServiceCollection services)
{
// 如果将 EnableDirectoryBrowsing 设为 true,记得注册服务
services.AddDirectoryBrowser();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// 启⽤ StaticFileMiddleware
// 启⽤ DefaultFilesMiddleware
// 禁⽤ DirectoryBrowserMiddleware
// 默认指向 wwwroot
app.UseFileServer();
/
/ 针对 files ⽂件夹配置
var fileServerOptions = new FileServerOptions
{
FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "files")),
RequestPath = "/files",
EnableDirectoryBrowsing = true
};
fileServerOptions.StaticFileOptions.OnPrepareResponse = ctx =>
{
// 配置缓存600s
ctx.Context.Response.Headers.Add(HeaderNames.CacheControl, "public,max-age=600");
};
fileServerOptions.DefaultFilesOptions.DefaultFileNames.Clear();
fileServerOptions.DefaultFilesOptions.DefaultFileNames.Add("myindex.html");
app.UseFileServer(fileServerOptions);
}
假如我们没有在DefaultFilesOptions.DefaultFileNames中添加⽂件名myindex.html,那么便不到默认页,但由于启⽤了DirectoryBrowsing,所以此时会展⽰⽂件列表。
核⼼配置项
FileProvider
上⾯我们已经见过PhysicalFileProvider了,它仅仅是众多⽂件提供程序中的⼀种。所有的⽂件提供程序均实现了IFileProvider接⼝:
public interface IFileProvider
{
// 获取给定路径的⽬录信息,可枚举该⽬录中的所有⽂件
IDirectoryContents GetDirectoryContents(string subpath);
// 获取给定路径的⽂件信息
IFileInfo GetFileInfo(string subpath);
// 创建指定 filter 的 ChangeToken
IChangeToken Watch(string filter);
}
public interface IDirectoryContents : IEnumerable<IFileInfo>, IEnumerable
{
bool Exists { get; }
}
public interface IFileInfo
{
bool Exists { get; }
bool IsDirectory { get; }
DateTimeOffset LastModified { get; }
// 字节(bytes)长度
// 如果是⽬录或⽂件不存在,则是 -1
long Length { get; }
// ⽬录或⽂件名,纯⽂件名,不包括路径
string Name { get; }
/
/ ⽂件路径,包含⽂件名
// 如果⽂件⽆法直接访问,则返回 null
string PhysicalPath { get; }
// 创建该⽂件只读流
Stream CreateReadStream();
}
常⽤的⽂件提供程序有以下三种:
PhysicalFileProvider
ManifestEmbeddedFileProvider
CompositeFileProvider
glob模式
在介绍这三种⽂件提供程序之前,先说⼀下glob模式,即通配符模式。两个通配符分别是*和**。
*:匹配当前⽬录层级(不包含⼦⽬录)下的任何内容、任何⽂件名或任何⽂件扩展名,可以通过/、\和.进⾏分隔。
**:匹配⽬录多层级(包含⼦⽬录)的任何内容,⽤于递归匹配多层级⽬录的多个⽂件。
PhysicalFileProvider
PhysicalFileProvider⽤于提供物理⽂件系统的访问。该提供程序需要将⽂件路径范围限定在⼀个⽬录及其⼦⽬录中,不能访问⽬录外部的内容。当实例化该⽂件提供程序时,需要提供⼀个绝对的⽬录路径,作为⽂件⽬录的root。
PhysicalFileProvider⽬录或⽂件路径不⽀持glob(通配符)模式。
ManifestEmbeddedFileProvider
ManifestEmbeddedFileProvider⽤于提供嵌⼊在程序集中的⽂件的访问。
可能你对这个嵌⼊⽂件⽐较陌⽣,没关系,请按照下⾯的步骤来:
安装Nuget包:Install-Package Microsoft.Extensions.FileProviders.Embedded
编辑.csproj⽂件:
添加<GenerateEmbeddedFilesManifest>,并设置为true
使⽤<EmbeddedResource>添加要嵌⼊的⽂件
以下是 .csproj ⽂件的⽰例:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="5.0.11" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="files\**" />
</ItemGroup>
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论