ASP.NET Core 2.2 基础知识(三) 静态文件
什么是静态文件?
HTML,CSS,JS,图片等都叫做静态文件.
要想提供静态文件给客户端,需要注册静态文件中间件.
我们先分别添加一个 WebAPI 项目,一个 Razor 视图项目,比较两个项目的 Startup 类的 Configure 方法:
WebAPI项目:

Razor项目:

可以看出,Razor项目多了一行代码 app.UseStaticFiles(); (下面那一行先不管)
这行代码的作用就是注册静态文件中间件.
UseStaticFiles() 方法的 xml 注释是这样写的 : Enables static file serving for the current request path.为当前请求路径提供静态文件服务.
之所以 WebAPI 项目没有注册静态文件中间件,是因为 WebAPI 的定义和 Razor,MVC 不一样.
我们再来比较一下 WebAPI 项目和 Razor 项目:

(Pages 文件夹先不管)
可以看出,Razor 项目多了一个叫 wwwroot 的东西.别看它图标是个球,其实它就是一个文件夹:

那么问题来了,既然 Razor 项目提供了静态文件中间件,那这个 wwwroot 文件夹里面的文件怎么访问呢?他们的路径是什么呢?
比如,我们现在要访问 wwwroot/css/site.css

当然,如果我们把 app.UseStaticFiles(); 注释掉,就404了:

从上面的例子中,可以看出,我们访问的是路径是: https://localhost:44301/css/site.css ,而不是 https://localhost:44301/wwwroot/css/site.css
显然,系统默认了 wwwroot 文件夹,那这个默认的路径在哪里可以看呢?
我们在 Pages 文件下的 Index.cshtml 页面中增加如下代码:(红色标注)

上面那行表示给 env 变量注入一个 IHostingEnvironment 类型的实例.
页面显示如下:

现在问题又来了,如果想访问 wwwroot 文件夹外的文件,应该怎么设置路径呢?
我们先添加一个文件夹 images,放入两张图片:

在 Startup 类中加入如下代码(红色标注):
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...other codes
app.UseStaticFiles();
//下面这个静态文件中间件的设置,只针对其设置的文件路径下的文件生效,和上面默认的静态文件路径 wwwroot 下的文件访问相互独立.
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "Images")),//设置文件路径(物理路径)
RequestPath = new PathString(@"/files"),//设置访问路径(虚拟路径)
OnPrepareResponse = context =>
{
context.Context.Response.Headers.Append("Cache-Control", "public,max-age=600");//设置缓存
},
});
...other codes
}
设置缓存的代码是顺带写的,仅仅表示有这个功能,跟设置路径没有关系.
请求自定义文件路径:

请求 wwwroot 文件夹下的文件:

可以看到,响应中没有缓存设置了,这证明了两者相互独立.
除了可以设置文件路径,访问路径,缓存外, StaticFileOptions 类还有3个属性:
1.ContentTypeProvider 内容提供器
它的功能,直接看代码就明白了.
var fileProvider = new FileExtensionContentTypeProvider();
fileProvider.Mappings.Remove(".jpg");//移除对 ".jpg" 文件的响应
fileProvider.Mappings[".laotie"] = "image/jpeg";//添加对 ".laotie" 文件的响应析,响应格式为 "image/jpeg" //下面这个静态文件中间件的设置,只针对其设置的文件路径下的文件生效,和上面默认的静态文件路径 wwwroot 下的文件访问相互独立.
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "Images")),//设置文件路径(物理路径)
RequestPath = new PathString(@"/files"),//设置访问路径(虚拟路径)
OnPrepareResponse = context =>
{
context.Context.Response.Headers.Append("Cache-Control", "public,max-age=600");//设置缓存
},
ContentTypeProvider = fileProvider,//设置文件提供器
});
我们再次请求 : https://localhost:44301/files/1.jpg

请求 : https://localhost:44301/files/3.laotie

2.ServeUnknownFileTypes
3.DefaultContentType
这两个属性一起说.
ServeUnknownFileTypes 的 xml 注释是这样写的 : If the file is not a recognized content-type should it be served?Default: false. 如果文件不是被认可的类型,那么它是否应该提供(给客户端)?默认:不提供.
那么哪些类型是认可的呢?太多了....截一小部分图:(这都是些啥类型啊,好诡异.小弟表示没见过)

如果 ServeUnknownFileTypes 设置为 true,则表示要提供(给客户端),而且是采用 DefaultContentType 属性设置的响应类型提供.
而 DefaultContentType 的 xml 注释是这样写的 :
//The default content type for a request if the ContentTypeProvider cannot determine one. 如果 ContentTypeProvider 属性设置的提供器不能选择出一个认可的类型,则采用该属性设置的响应类型.
//None is provided by default, so the client must determine the format themselves.如果该属性没有提供响应类型(即该属性没有值,为null),则交给客户端来格式化它们.
测试如下:
我们将 上述代码中的 fileProvider.Mappings[".laotie"] = "image/jpeg" 注释掉,注释后的完整代码如下:
var fileProvider = new FileExtensionContentTypeProvider();
fileProvider.Mappings.Remove(".jpg");//移除对 ".jpg" 文件的解析
//fileProvider.Mappings[".laotie"] = "image/jpeg";//添加对 ".laotie" 文件的解析,解析方式为 "image/jpeg" //下面这个静态文件中间件的设置,只针对其设置的文件路径下的文件生效,和上面默认的静态文件路径 wwwroot 下的文件访问相互独立.
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "Images")),//设置文件路径(物理路径)
RequestPath = new PathString(@"/files"),//设置访问路径(虚拟路径)
OnPrepareResponse = context =>
{
context.Context.Response.Headers.Append("Cache-Control", "public,max-age=600");//设置缓存
},
ContentTypeProvider = fileProvider,//设置文件提供器
});
我们再次请求 https://localhost:44301/files/3.laotie , 结果 404,因为我们删掉了对 ".老铁" 文件类型的认可,而 ServeUnknownFileTypes 默认值又为 false

当我们把 ServeUnknownFileTypes 属性设置为 ture :
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "Images")),//设置文件路径(物理路径)
RequestPath = new PathString(@"/files"),//设置访问路径(虚拟路径)
OnPrepareResponse = context =>
{
context.Context.Response.Headers.Append("Cache-Control", "public,max-age=600");//设置缓存
},
ContentTypeProvider = fileProvider,//设置文件提供器
ServeUnknownFileTypes = true,
});
再次请求 https://localhost:44301/files/3.laotie ,则正常显示出了内容(图就不上了)
我以为:如果设置 DefaultContentType = "text/plain" ,那么 3.laotie 应该不能正常访问,但实际上还是可以访问.有点不明白.希望高手解答一下.
跟文件访问相关的中间件,除了上面提到的静态文件中间件外,还有两个:
1.默认文件中间件 app.UseDefaultFiles()
默认文件中间件的默认文件有4种:default.htm,default.html,index.htm,index.html
当然,我们也可以自定义.
下面的示例给出了默认中间件的相关功能.
//提供默认文件
DefaultFilesOptions options = new DefaultFilesOptions
{
FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "Default")),
};
options.DefaultFileNames.Add("mydefault.html");//添加自定义的默认文件
app.UseDefaultFiles(options); app.UseStaticFiles(); //使用静态文件中间件
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "Default"))
});
有两点要特别注意:
1)必须在 UseStaticFiles 前调用 UseDefaultFiles .UseDefaultFiles 实际上用于重写 URL,不提供文件,真正提供文件的依然是 UseStaticFiles .
2)两个中间件的路径必须设置一样.理由就是第一条.
2.目录浏览中间件 app.UseDirectoryBrowser()
该中间件的启用方式,设置方式和静态文件中间件类似.
由于涉及安全考虑,微软默认没有启动该中间件.
//启用目录浏览中间件
app.UseDirectoryBrowser();
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "Images")),
RequestPath = new PathString(@"/files"),
});
除了上述3种文件相关的中间件外,系统提供了一个3合一的中间件:
//同时启用默认的静态文件,默认文件,静态目录浏览中间件,false 则不启动静态目录浏览.
app.UseFileServer(true);
处于安全考虑,要启动目录浏览中间件,需要传入 true .
完.
ASP.NET Core 2.2 基础知识(三) 静态文件的更多相关文章
- ASP.NET Core 2.2 基础知识(十八) 托管和部署 概述
为了方便演示,以 .NET Core 控制台应用程序讲解. 我们新建一个控制台应用程序,安装 "Newtonsoft.Json" Nuget 包,然后右键点击该项目,选择" ...
- ASP.NET Core 2.2 基础知识(十四) WebAPI Action返回类型(未完待续)
要啥自行车,直接看手表 //返回基元类型 public string Get() { return "hello world"; } //返回复杂类型 public Person ...
- ASP.NET Core 2.2 基础知识(十二) 发送 HTTP 请求
可以注册 IHttpClientFactory 并将其用于配置和创建应用中的 HttpClient 实例. 这能带来以下好处: 提供一个中心位置,用于命名和配置逻辑 HttpClient 实例. 例如 ...
- ASP.NET Core 2.2 基础知识(十) Web服务器 - Kestrel
ASP.NET Core 应用与进程内的 HTTP 服务器实现一起运行.该服务器实现侦听 HTTP 请求,并在一系列请求功能被写到 HttpContext 时,将这些请求展现到应用中. ASP.NET ...
- ASP.NET Core 2.2 基础知识(六) 配置(内含MySql+EF)
先上一段代码,了解一下 .NET Core 配置数据的结构. 新建一个 控制台项目,添加一个文件 json.json ,文件内容如下: { "country": "cn& ...
- ASP.NET Core 2.2 基础知识(十六) SignalR 概述
我一直觉得学习的最好方法就是先让程序能够正常运行,才去学习他的原理,剖析他的细节. 就好像这个图: 所以,我们先跟着官方文档,创建一个 SignalR 应用: https://docs.microso ...
- ASP.NET Core 2.2 基础知识(十三) WebAPI 概述
我们先创建一个 WebAPI 项目,看看官方给的模板到底有哪些东西 官方给出的模板: [Route("api/[controller]")] [ApiController] pub ...
- ASP.NET Core 2.2 基础知识(十一) ASP.NET Core 模块
ASP.NET Core 应用与进程内的 HTTP 服务器实现一起运行.该服务器实现侦听 HTTP 请求,并在一系列请求功能被写到 HttpContext 时,将这些请求展现到应用中. ASP.NET ...
- ASP.NET Core 2.2 基础知识(九) 使用托管服务实现后台任务
在 ASP.NET Core 中,后台任务作为托管服务实现.托管服务是一个类,而且必须实现 IHostedService 接口,该接口定义了两个方法: StartAsync(CancellationT ...
随机推荐
- 假的kd-tree小结
至今还不是很体会kd-tree这种东西,只不过体会了一种解决某些枚举问题的方法,就是当我们有一群元素,我们要到一个答案,答案在这些元素中的某个或某几个中,我们就会枚举他们,然而我们发现这样做十分低效, ...
- 【BZOJ 4103】 [Thu Summer Camp 2015]异或运算 可持久化01Trie
我们观察数据:树套树 PASS 主席树 PASS 一层一个Trie PASS 再看,异或!我们就把目光暂时定在01Tire然后我们发现,我们可以带着一堆点在01Trie上行走,因为O(n*q* ...
- [USACO08DEC] 秘密消息Secret Message
题目描述 Bessie is leading the cows in an attempt to escape! To do this, the cows are sending secret bin ...
- JSOI2008 星球大战 [并查集]
题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系. 某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球通过特殊的以太隧 ...
- [poj 2796]单调栈
题目链接:http://poj.org/problem?id=2796 单调栈可以O(n)得到以每个位置为最小值,向左右最多扩展到哪里. #include<cstdio> #include ...
- intellij IDEA与springboot项目建立
概念问题: IntelliJ系中的Project相当于Eclipse系中的workspace.IntelliJ系中的Module相当于Eclipse系中的Project.IntelliJ中一个Proj ...
- oracle与mysql的group by语句
之所以去纠那么细节的问题,是因为之前有过一个这样的场景: 有个同学,给了一条数据库的语句给我,问,为啥这样子的语句在oracle语句下执行不了. 1 select * from xx where xx ...
- 搭建jfinal+maven框架
1.创建一个maven web项目. 2.添加引用包 <dependency> <groupId>com.jfinal</grou ...
- 【HDU】6146 Pokémon GO
[题意]一个2*n的网格,再保证步数最少的情况下,求从任意格出发遍历完所有格的方案数,格子八连通.n<=10000,T<=100. [算法]递推,DP [题解]原题链接:蓝桥杯 格子刷油漆 ...
- Python学习笔记 - day6 - 函数
函数 函数在编程语言中就是完成特定功能的一个词句组(代码块),这组语句可以作为一个单位使用,并且给它取一个名字.可以通过函数名在程序的不同地方多次执行(这叫函数的调用).函数在编程语言中有基本分为:预 ...