通过调用ApplicationBuilder的扩展方法UseStaticFiles注册的StaticFileMiddleware中间件帮助我们处理针对文件的请求。对于StaticFileMiddleware处理请求的逻辑,大部分读者都应该想得到:它根据请求的地址找到目标文件的路径,然后利用注册的ContentTypeProvider根据路径解析出与文件内容相匹配的媒体类型,默认情况下得到的媒体类型是根据目标文件的扩展名解析出来的。解析出来的媒体类型将作为响应报头Content-Type的值。StaticFileMiddleware中间件最终利用FileProvider读取文件的内容作为响应消息的主体。实际上,这个中间件在处理请求时比我们想象的要多得多,针对条件请求(Conditional Request)区间请求(Range Request)的处理就没有在上面演示的实例中体现出来。 [本文已经同步到《ASP.NET Core框架揭秘》之中]

目录
一、条件请求
    HTTP条件请求
    针对静态文件的条件请求
二、 区间请求
    HTTP区间请求
    针对静态文件的区间请求

所谓的条件请求就是客户端在发送GET请求获取某种资源的时候,会利用请求报头携带一些条件。服务端处理器在接受到这样的请求之后,会提取这些条件并验证目标资源的当前的状态是否满足客户端指定的条件。在有在这些条件满足的情况下,目标资源的内容才会真正响应给客户端。

HTTP条件请求

HTTP条件请求作为一项标准记录在HTTP规范中。一般来说,一个GET请求在目标资源存在的情况下总是会返回一个状态为“200 OK”的响应,目标资源的内容将直接存放在响应消息的主体部分。如果资源的内容不会轻易改变,我们希望客户端(比如浏览器)在本地缓存获取的资源。对于由它发送的针对同一资源的后续请求,如果资源内容不曾改变,那么资源的内容则无需再次作为网络负载予以响应。这就是条件请求需要解决的一个典型场景。

确定资源是否发生变化可以采用两种策略。第一种就是让资源的提供者记录下最后一次更新资源的时间,资源的负载和这个时间戳将一并作为响应提供给作为请求发送者的客户端。客户端在缓存资源自身内容的同时也会保存这个时间戳。等到下次针对同一资源发送请求,它会将这个时间戳一并发送出去,那么服务端就可以根据这个时间戳判断目标资源在上次响应之后是否被修改过。除了采用记录资源最后修改时间的方式外,我们还可以针对资源的内容生成一个“签名”,签名的一致性体现了资源内容的一致性,在HTTP规范中将这个签名成为ETag(Entity Tag)。

接下来我们从HTTP请求和响应报文的层面对条件请求进行详细介绍。对于HTTP请求来说,缓存资源携带的最后修改时间戳ETag分别保存在名为If-Modified-SinceIf-None-Match的报头中。报头名称体现的意思是如果目标资源在指定的时间之后被修过(If-Modified-Since)或者目前资源的状态与提供ETag的不匹配(If-None-Match)才将目标资源的内容作为响应负载返回。

当服务端接收到针对某个资源的GET请求,如果请求不具有上述这两个报头或者根据这两个报头携带的信息判断资源已经发生改变,在的情况下会返回一个状态码为“200 OK”的响应。除了将资源内容作为响应主体之外,如果能够获取到该资源最后一次修改的时间(一般精确到秒),格式化的时间戳将保存到一个名为Last-Modified的报头中。至于针对资源自身内容生成的签名,对应的报头名称就是ETag。反之,如果做出相反的判断,服务端会响应一个状态码为“304 Not Modified”的响应,这个响应不具有主体。一般来说,这样的响应也会携带Last-Modified和ETag报头。

与条件请求相关的请求报头还具有额外两个,即If-Unmodified-Since和If -Match,它们具有与If-Modified-Since和If-None-Match完全相反的语义,分别表示如果目标资源在指定时间之后没有被修改(If-Unmodified-Since)或者目标资源目前的ETag与提供的ETag匹配(If-Match)的请求下才将资源作为响应负载返回。针对这样的请求,如果根据携带的这两个报头判断出目标资源并不曾发生变化,服务端会返回一个将资源内容作为主体的“200 OK”响应,这样的响应也会携带Last-Modified和If-Match报头。反之,如果做出了相反的判断,服务端会响应一个状态码为“412 Precondition Failed”的响应。

针对静态文件的条件请求

接下来我们通过实例演示的形式来介绍StaticFileMiddleware中间件在针对条件请求方面做了些什么。假设我们在ASP.NET Core应用中发布一个文本文件(foobar.txt),内容为“abcdefghijklmnopqrstuvwxyz0123456789”(26个字母+10个数字),目标地址为“http://localhost:5000/foobar.txt”。现在我们直接利用Fiddler针对这个地址发送一个普通的GET请求,看看会得到怎样的响应。

.1
   2: Host: localhost:5000
   3:  
.1 200 OK
   5: Date: Thu, 10 Nov 2016 13:01:59 GMT
   6: Content-Length: 39
   7: Content-Type: text/plain
   8: Server: Kestrel
Last-Modified: Thu, 10 Nov 2016 01:43:37 GMT
  10: Accept-Ranges: bytes
  12:  
  13: abcdefghijklmnopqrstuvwxyz0123456789

相关文章:

  • 2021-06-06
  • 2023-02-15
  • 2021-10-28
  • 2021-09-18
  • 2022-12-23
  • 2022-12-23
  • 2021-07-30
猜你喜欢
  • 2021-05-26
  • 2022-02-01
  • 2021-05-28
  • 2021-09-23
  • 2022-12-23
  • 2022-01-10
相关资源
相似解决方案