在上一篇文章中,我们介绍了客户端如何与服务器建立起连接,那么这篇文章中,将介绍服务器接收到连接以后,又怎样把HTTP消息进行路由和处理的常规流程。这里重点将介绍HOST这个请求头部。
HOST头部
- HOST = uri-host [":" port] (ABNF对它的定义)
- HTTP/1.1规范要求,不传递Host头部则返回400错误响应码(为什么HTTP/1.1规范要加入这样一个要求呢?因为在HTTP/1.0这个版本中,是没有HOST头部的。因为HTTP/1.0所在的上世纪90年代中,域名相对是比较少的,每一个服务器的ip地址仅对应一个域名,所以当用户已经对你的服务器建立起连接以后,你是不需要考虑匹配那个域名对应的服务的。但是后来我们发现,HTTP域名众多,但是ip地址相对比较少,所以我们引入了HOST头部。)
- 为防止HTTP/1.0时代的陈旧的代理服务器还在我们的网络中,发向正向代理的请求request-target必须以absolute-form形式出现
- request-line = method SP request-target SP HTTP-version CRLF
- absolute-form = absolute-URI
- absolute-URI = scheme ":" hier-part ["?" query ]
规范和实现间是有差距的
- 关于Host头部:https://tools.ietf.org/html/rfc7230#section-5.4
- A cliend MUST send a Host header field in all HTTP/1.1 request messages.
- A server MUST respond with a 400 (Bad Request) status code to any HTTP/1.1 request message that lacks a Host header field and to any request message that contains more than one Host header field or a Host header field with an invalid field-value.
Host头部与消息的路由
(这里我们以典型的nginx来处理HOST头部的流程,来演示大部分的Web服务器在建立好TCP连接以后,究竟是怎样来寻找消息的处理模块的)
- 建立TCP连接
- 确定服务器的ip地址
- 接收请求
- 寻找虚拟主机
- 匹配Host头部域名(请求行URI中,可能拿到了absolute-form,也就是绝对形式中因为这里可以取到域名,或者从Header中的Host头部也可以取到域名,拿到这个域名以后,就会和这台Web服务器所支持的所有域名进行匹配,匹配选中以后,就会选中相应的模块进行处理)
- 寻找URI的处理代码(接着进行第二步的路由匹配,就是按照URI中的Path路径,一一匹配相应的代码,找到处理请求的代码,然后开始访问相应的资源)
- 匹配URI
- 执行处理请求的代码
- 访问资源
- 生成HTTP响应
- 各中间件基于PF架构串行修改响应
- 发送HTTP响应
- 记录访问日志
小结
这篇文章中介绍了HOST头部,以及如何基于HOST进行消息的路由,这里我们所介绍的服务器根据HOST头部路由的流程,与大多数Web服务器相似,对我们具有参考价值。