本文摘自书籍《HTTP 权威指南》
此系列文章对应 github地址
Web服务器
Web 服务器实现了 HTTP 和相关的 TCP 连接处理。负责管理 Web 服务器提供的资源,以及对 Web 服务器的配置、控制及扩展方面的管理。Web 服务器逻辑实现了 HTTP 协议、管理着 Web 资源,并负责提供 Web 服务器的管理功能。Web 服务器逻辑和操作系统共同负责管理 TCP 连接。底层操作系统负责管理底层计算机系统的硬件细节,并提供了 TCP/IP 网络支持、负责装载 Web 资源的文件系统以及控制当前计算活动的进程管理功能。Web 服务器有各种不同的形式:
- 可以在标准的计算机系统上安装并运行通用的软件 Web 服务器。
- 如果不想那么麻烦地去安装软件,可以买一台 Web 服务器设备,通常会是一台安装在时髦机架上的计算机,里面的软件会预装并配置好。
- 随着微处理器奇迹般地出现,有些公司甚至可以在少量计算机芯片上实现嵌入式 Web 服务器,使其成为完美的(便携式)消费类设备管理控制台。
Web服务器基本任务
- 建立连接——接受一个客户端连接,或者如果不希望与这个客户端建立连接,就将其关闭。
- 接收请求——从网络中读取一条 HTTP 请求报文。
- 处理请求——对请求报文进行解释,并采取行动。
- 访问资源——访问报文中指定的资源。
- 构建响应——创建带有正确首部的 HTTP 响应报文。
- 发送响应——将响应回送给客户端。
- 记录事务处理过程——将与已完成事务有关的内容记录在一个日志文件中。
建立连接
处理新连接
客户端请求一条到 Web 服务器的 TCP 连接时,Web 服务器会建立连接,判断连接的另一端是哪个客户端,从 TCP 连接中将 IP 地址解析出来。 一旦新连接建立起来并被接受,服务器就会将新连接添加到其现存 Web 服务器连接列表中,做好监视连接上数据传输的准备。Web 服务器可以随意拒绝或立即关闭任意一条连接。有些 Web 服务器会因为客户端 IP 地址或主机名是未认证的,或者因为它是已知的恶意客户端而关闭连接。Web 服务器也可以使用其他识别技术。
客户端主机名识别
可以用“反向 DNS”对大部分 Web 服务器进行配置,以便将客户端 IP 地址转换成客户端主机名。Web 服务器可以将客户端主机名用于详细的访问控制和日志记录。但要注意的是,主机名查找可能会花费很长时间,这样会降低 Web 事务处理的速度。很多大容量 Web 服务器要么会禁止主机名解析,要么只允许对特定内容进行 解析。
通过ident确定客户端用户
有些 Web 服务器还支持 IETF 的 ident 协议。服务器可以通过 ident 协议找到发起 HTTP 连接的用户名。这些信息对 Web 服务器的日志记录特别有用。如果客户端支持 ident 协议,就在 TCP 端口 113 上监听 ident 请求。客户端打开了一条 HTTP 连接。然后,服务器打开自己到客户端 ident 服务器端口(113)的连接,发送一条简单的请求,询问与(由客户端和服务器端口号指定的)新连接相对应的用户名,并从客户端解析出包含用户名的响应。ident 在组织内部可以很好地工作,但出于多种原因,在公共因特网上并不能很好地工作,原因包括:
- 很多客户端 PC 没有运行 ident 识别协议守护进程软件
- ident 协议会使 HTTP 事务处理产生严重的时延
- 很多防火墙不允许 ident 流量进入
- ident 协议不安全,容易被伪造
- ident 协议也不支持虚拟 IP 地址
- 暴露客户端的用户名还涉及隐私问题
接收请求
连接上有数据到达时,Web 服务器会从网络连接中读取数据,并将请求报文中的内容解析出来。解析请求报文时,Web 服务器会:
- 解析请求行,查找请求方法、指定的资源标识符(URI)以及版本号,各项之间由一个空格分隔,并以一个回车换行(CRLF)序列作为行的结束。
- 读取以 CRLF 结尾的报文首部。
- 检测到以 CRLF 结尾的、标识首部结束的空行(如果有的话)。
- 如果有的话(长度由 Content-Length 首部指定),读取请求主体。
报文的内部表示法
有些 Web 服务器还会用便于进行报文操作的内部数据结构来存储请求报文。比如,数据结构中可能包含有指向请求报文中各个片段的指针及其长度,这样就可以将这些首部存放在一个快速查询表中,以便快速访问特定首部的具体值了。
连接的输入/输出处理结构
高性能的 Web 服务器能够同时支持数千条连接。这些连接使得服务器可以与世界各地的客户端进行通信,每个客户端都向服务器打开了一条或多条连接。某些连接可能在快速地向 Web 服务器发送请求,而其他一些连接则可能在慢慢发送,或者不经常发送请求,还有一些可能是空闲的,安静地等待着将来可能出现的动作。因为请求可能会在任意时刻到达,所以 Web 服务器会不停地观察有无新的 Web 请求。不同的 Web 服务器结构会以不同的方式为请求服务。
单线程web服务器
单线程的 Web 服务器一次只处理一个请求,直到其完成为止。一个事务处理结束之后,才去处理下一条连接。这种结构易于实现,但在处理过程中,所有其他连接都会被忽略。这样会造成严重的性能问题,只适用于低负荷的服务器,以及 type-o-serve 这样的诊断工具。
多进程及多线程 Web 服务器
多进程和多线程 Web 服务器用多个进程,或更高效的线程同时对请求进行处理。可以根据需要创建,或者预先创建一些线程 / 进程。有些服务器会为每条连接 分配一个线程 / 进程,但当服务器同时要处理成百、上千,甚至数以万计的连接 时,需要的进程或线程数量可能会消耗太多的内存或系统资源。因此,很多多线程 Web 服务器都会对线程 / 进程的最大数量进行限制。
复用 I/O 的服务器
为了支持大量的连接,很多 Web 服务器都采用了复用结构。在复用结构中,要同时监视所有连接上的活动。当连接的状态发生变化时(比如,有数据可用,或出现错误时),就对那条连接进行少量的处理;处理结束之后,将连接返回到开放连接列表中,等待下一次状态变化。只有在有事情可做时才会对连接进行处理;在空闲连接上等待的时候并不会绑定线程和进程。
复用的多线程 Web 服务器
有些系统会将多线程和复用功能结合在一起,以利用计算机平台上的多个 CPU。多个线程(通常是一个物理处理器)中的每一个都在观察打开的连接(或打开的连接中的一个子集),并对每条连接执行少量的任务。
处理请求
一旦 Web 服务器收到了请求,就可以根据方法、资源、首部和可选的主体部分来对请求进行处理了。有些方法(比如 POST)要求请求报文中必须带有实体主体部分的数据。其他一些方法(比如 OPTIONS)允许有请求的主体部分,也允许没有。少数方法(比如 GET)禁止在请求报文中包含实体的主体数据。
访问资源
Web 服务器是资源服务器。它们负责发送预先创建好的内容,比如 HTML 页面或 JPEG 图片,以及运行在服务器上的资源生成程序所产生的动态内容。在 Web 服务器将内容传送给客户端之前,要将请求报文中的 URI 映射为 Web 服务 器上适当的内容或内容生成器,以识别出内容的源头。
构建响应
一旦 Web 服务器识别出了资源,就执行请求方法中描述的动作,并返回响应报文。响应报文中包含有响应状态码、响应首部,如果生成了响应主体的话,还包括响应主体。
响应实体
如果事务处理产生了响应主体,就将内容放在响应报文中回送过去。如果有响应主体的话,响应报文中通常包括:
- 描述了响应主体 MIME 类型的 Content-Type 首部;
- 描述了响应主体长度的 Content-Length 首部;
- 实际报文的主体内容。
MIME类型
Web 服务器要负责确定响应主体的 MIME 类型。有很多配置服务器的方法可以将 MIME 类型与资源关联起来。
重定向
Web 服务器有时会返回重定向响应而不是成功的报文。 Web 服务器可以将浏览器重定向到其他地方来执行请求。重定向响应由返回码 3XX 说明。Location 响应首部包含了内容的新地址或优选地址的 URI。重定向可用于下列情况:
永久搬离的资源
资源可能已经被移动到了新的位置,或者被重新命名,有了一个新的 URL。Web 服务器可以告诉客户端资源已经被重命名了,这样客户端就可以在从新地址获取资源之前,更新书签之类的信息了。状态码 301 Moved Permanently 就用于此类重定向。
临时搬离的资源
如果资源被临时移走或重命名了,服务器可能希望将客户端重定向到新的位置上去。但由于重命名是临时的,所以服务器希望客户端将来还可以回头去使用老的 URL,不要对书签进行更新。状态码 303 See Other 以及状态码 307 Temporary Redirect 就用于此类重定向。
URL 增强
服务器通常用重定向来重写 URL,往往用于嵌入上下文。当请求到达时,服务器会生成一个新的包含了嵌入式状态信息的 URL,并将用户重定向到这个新的 URL 上去。客户端会跟随这个重定向信息,重新发起请求,但这次的请求会包含完整的、经过状态增强的 URL。这是在事务间维护状态的一种有效方式。状态码 303 See Other 和 307 Temporary Redirect 用于此类重定向。
负载均衡
如果一个超载的服务器收到一条请求,服务器可以将客户端重定向到一个负载不太重的服务器上去。状态码 303 See Other 和 307 Temporary Redirect 可用于此类重定向。
服务器关联
Web 服务器上可能会有某些用户的本地信息;服务器可以将客户端重定向到包含了那个客户端信息的服务器上去。状态码 303 See Other 和 307 Temporary Redirect 可用于此类重定向。
规范目录名称
客户端请求的 URI 是一个不带尾部斜线的目录名时,大多数 Web 服务器都会将客户端重定向到一个加了斜线的 URI 上,这样相对链接就可以正常工作了。
发送响应
Web 服务器通过连接发送数据时也会面临与接收数据一样的问题。服务器可能有很多条到各个客户端的连接,有些是空闲的,有些在向服务器发送数据,还有一些在向客户端回送响应数据。服务器要记录连接的状态,还要特别注意对持久连接的处理。对非持久连接而言,服务器应该在发送了整条报文之后,关闭自己这一端的连接。对持久连接来说,连接可能仍保持打开状态,在这种情况下,服务器要特别小心,要正确地计算 Content-Length 首部,不然客户端就无法知道响应什么时候结束了。
记录日志
当事务结束时,Web 服务器会在日志文件中添加一个条目,来描述已执行的事务。