1 Overviews
我们都知道 Asp.NET Core
应用程序就是对 HttpContext
对象的处理,但是我们可以为 ASP.NET Core
选择不同的服务器,所以不同的服务器与 HttpContext
之间的适配就成了主要的问题。因此 Asp.NET Core
提供了 IFeature
这样的通用的接口,任何服务器只要实现了这样的接口,就可以直接构造出 HttpContext
这样的对象。
接下来我们看一看都有哪些 Features
。
2 Features
2.1 IHttpConnectionFeature
它代表了一个 HTTP 连接下层的 TCP/IP (Socket) 来连接,我们都知道一个 TCP 连接是四元组 (源IP,源端口,目标IP,目标端口)
,同时还有一个 id 用来表示当前的连接
2.2 IHttpRequestFeature
表示一个 Http Request 请求. protocol
表明是 HTTP 的版本; Schema
说明是 http
还是 https
; Method
表明是 GET
, POST
等请求方法;
假设我们有这样一个请求地址
https://localhost:80/api/rollout/456?detail=true
- PathBase:
/api
- Path:
/api/rollout/456
- QueryString:
?detail=true
- RawTarget:
/api/rollout/456?detail=true
Header
字典记录了 HTTP
请求的 Header
的内容,假设我们的 header 是这样的
HeaderA: value1, value2
HeaderA: value3
那么 Header
中记录的形式是这样的 Headers["HeaderA"]={"value1", "value2", "value3"}
2.3 IRequestCookiesFeature
代表了请求中的 Cookies
, 它返回了一个 IRequestCookieCollection
对象。 请求中的 Cookies
是放在 Header
中,格式如下
Cookie: SID=31d4d96e407aad42; lang=en-US
那么 IRequestCookieCollection
保存的数据就是
SID: 31d4d96e407aad42
lang: en-US
2.4 IFormFeature
2.5 IFormFeature
在 HTML
页面中,可以通过下面的方式发送 form
数据
<form action="https://example.com" method="POST">
</form>
发送的请求时候, Header
中的 Content-Type
包含下面三种选项
application/x-www-form-urlencoded
: 它说明了form
中的key-value
对按照&
和=
的方式组合在一起放在 body 中,比如说
POST /test HTTP/1.1
Host: example
Content-Type: application/x-www-form-urlencoded
Content-Length: 27
field1=value1&field2=value2
Multipart/form-data
如果form
中包含了大的二进制文件,需要拆开开,并且使用boundary
指定的字符进行拆分。在每一个部分中,用Content-Disposition
之后的内容表示各自的key-value
对
POST /test HTTP/1.1
Host: foo.example
Content-Type: multipart/form-data;boundary="boundary"
--boundary
Content-Disposition: form-data; name="field1"
value1
--boundary
Content-Disposition: form-data; name="field2"; filename="example.txt"
value2
--boundary--
有了这些基础知识,我们来看看 IFormFeature
究竟做了什么事情
HasFormContentType
说明是否包含了Form
的请求Form, ReadForm, ReadFormAsync
都是读取出IFormCollection
IFormCollection
中,
前 5 项是关于是application/x-www-form-urlencoded
form 中包含的记录,而 Files
则记录了 Multipart/form-data
form 中的数据。 IFormFileCollection
则是 IFormFile
的集合,可以通过 name
索引读取,需要注意的是多个块可以包含相同的 name
.
2.6 IRequestCookiesFeature
这是请求发过来的 cookie
, 一般来讲请求的 cookie
是这样的
GET /sample_page.html HTTP/2.0
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry
在 Cookie
的 header 项中,通过 ;
和 =
将多个 key-value
组合在一起。 IRequestCookiesFeature
就保存着这些 key-value
对。
2.7 IHttpWebSocketFeature
首先什么是 WebSocket
, 我们都知道 HTTP
请求是单向的,也就是说只有客户端发送请求之后,服务端将数据发送给客户端;在长时间运行的服务中,如果客户端想要得到最新的服务端数据,需要采取定期 poll 服务端。那么 WebSocket
出现就解决了这个问题,它允许客户端和服务端双向发送数据,这样一旦服务发现了新的数据,就可以向客户端直接发送,从而避免了不停的 poll 的策略。
WebSocket
的连接的建立是基于 Http
请求
GET ws://example.com:8181/ HTTP/1.1
Host: localhost:8181
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: q4xkcO32u266gldTuKaSOw==
ws://example.com:8181
执行了Websocket
的协议,而且是开始于HTTP/1.1
协议Connection:Upgrade
确定当前的连接是升级了Upgrade:websocket
表明升级到Websocket
协议Sec-Websocket-Version
指定WebSocket
的版本Sec-WebSockety-key
随机生成的 16 个字节base64
编码后的值
那么服务端返回的数据就是
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: fA9dggdnMPU79lJgAE3W4TRnyDM=
HTTP/1.1 101
转换协议Upgrade
修改协议为WebSocket
Sec-WebSocket-Accept
将客户端发过来的Sec-WebSocket-Key
和 `258EAFA5-E914–47DA-95CA-C5AB0DC85B11` 拼接后的base64
值。
基于上述 WebSocket
的基本认知, IHttpWebSocketFeature
主要工作首先是否判断可以转换成 WebSocket
,如果是则调用 AcceptAsync
转换成一个 WebSocket
对象。
2.8 IHttpResponseFeature
StatusCode
HTTP 请求的 status codeReasonPhrase
StatusCode
中的文本解释,比如OK
,Not Found
等等,注意这个不是个 Optional 的Headers
响应的header
Body
请求Body
的Stream
OnStarting OnCompleted
当Response
开始,完成的时候,注册相关的操作。
2.9 IHttpResponseBodyFeature
Stream
用来写 body 的 StreamWriter
用来写 body 的 WriterStartAsync
调用OnStarting
方法,并且让Headers
只读SendFileAsync
发送请求的文件CompleteAsync
Flush 剩下的header
data
等等。
2.10 IResponseCookiesFeature
和 IRequestCookiesFeature
相呼应, IResponseCookies
,一个典型的 Response
的 cookie 是这样的
HTTP/2.0 200 OK
Content-Type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry
但是不同于 Request
中直接的 Cookie
, response 中的 cookie
可以由额外的配置选项,比如
Expires
设置Cookie
过期时间Secure
设置 cookie只能在HTTPS
协议中使用- ...
这些都通过 CookieOptions
来配置