HTTP的WEB服务器做了些什么?

Web服务器的实现

Web 服务器实现了 HTTP 和相关的 TCP 连接处理。 负责管理 Web 服务器提供的资源, 以及对 Web 服务器的配置、 控制及扩展方面的管理。

Web 服务器逻辑实现了 HTTP 协议、 管理着 Web 资源, 并负责提供 Web 服务器的管理功能。 Web 服务器逻辑和操作系统共同负责管理 TCP 连接。 底层操作系统负责管理底层计算机系统的硬件细节, 并提供了 TCP/IP 网络支持、 负责装载 Web 资源的文件系统以及控制当前计算活动的进程管理功能。

Web 服务器有各种不同的形式。

  • 可以在标准的计算机系统上安装并运行通用的软件 Web 服务器。
  • 如果不想那么麻烦地去安装软件, 可以买一台 Web 服务器设备, 通常会是一台安装在时髦机架上的计算机, 里面的软件会预装并配置好。
  • 随着微处理器奇迹般地出现, 有些公司甚至可以在少量计算机芯片上实现嵌入式Web 服务器, 使其成为完美的(便携式) 消费类设备管理控制台。

Web服务器设备

Web 服务器设备(Web server appliance) 是预先打包好的软硬件解决方案。 厂商会在他们选择的计算机平台上预先安装好软件服务器, 并将软件配置好。

下面是一些Web 服务器设备的例子:

  • Sun/Cobalt RaQ Web 设备(http://www.cobalt.com) ;
  • 东芝的 Magnia SG10(http://www.toshiba.com);
  • IBM 的 Whistle Web 服务器设备(http://www.whistle.com)。
    应用解决方案不再需要安装及配置软件, 通常可以极大地简化管理工作。 但是,Web 服务器通常不太灵活, 特性不太丰富, 而且服务器硬件也不太容易重用或升级

嵌入式Web服务器

嵌入式服务器(embeded server) 是要嵌入到消费类产品(比如打印机或家用设备)中去的小型 Web 服务器。 嵌入式 Web 服务器允许用户通过便捷的 Web 浏览器接口来管理其消费者设备。 有些嵌入式 Web 服务器甚至可以在小于一平方英寸的空间内实现, 但通常只能提供最小特性功能集。

下面是两种非常小的嵌入式 Web 服务器实例:

实际的Web服务器会做些什么

(1) 建立连接——接受一个客户端连接, 或者如果不希望与这个客户端建立连接, 就
将其关闭。
(2) 接收请求——从网络中读取一条 HTTP 请求报文。
(3) 处理请求——对请求报文进行解释, 并采取行动。
(4) 访问资源——访问报文中指定的资源。
(5) 构建响应——创建带有正确首部的 HTTP 响应报文。
(6) 发送响应——将响应回送给客户端。
(7) 记录事务处理过程——将与已完成事务有关的内容记录在一个日志文件中。

image

第一步——接受客户端连接

处理新连接

客户端请求一条到 Web 服务器的 TCP 连接时, Web 服务器会建立连接, 判断连接的另一端是哪个客户端, 从 TCP 连接中将 IP 地址解析出来。一旦新连接建立起来并被接受, 服务器就会将新连接添加到其现存 Web 服务器连接列表中, 做好监视连接上数据传输的准备。

Web 服务器可以随意拒绝或立即关闭任意一条连接。 有些 Web 服务器会因为客户
端 IP 地址或主机名是未认证的, 或者因为它是已知的恶意客户端而关闭连接。 Web
服务器也可以使用其他识别技术。

客户端主机名识别

可以用“反向 DNS” 对大部分 Web 服务器进行配置, 以便将客户端 IP 地址转换成客户端主机名。 Web 服务器可以将客户端主机名用于详细的访问控制和日志记录。但要注意的是, 主机名查找可能会花费很长时间, 这样会降低 Web 事务处理的速度。 很多大容量 Web 服务器要么会禁止主机名解析, 要么只允许对特定内容进行解析。

可以用配置指令 HostnameLookups 启用 Apache 的主机查找功能。 比如, 例 5-2 中
的 Apache 配置指令就只打开了 HTML 和 CGI 资源的主机名解析功能。

配置 Apache, 为 HTML 和 CGI 资源查找主机名

HostnameLookups off
<Files ~ "\.(html|htm|cgi)$">
HostnameLookups on
</Files>

通过ident确定客户端用户

有些 Web 服务器还支持 IETF 的 ident 协议。 服务器可以通过 ident 协议找到发起
HTTP 连接的用户名。 这些信息对 Web 服务器的日志记录特别有用——流行的通用
日志格式(Common Log Format) 的第二个字段中就包含了每条 HTTP 请求的 ident
用户名

如果客户端支持 ident 协议, 就在 TCP 端口 113 上监听 ident 请求。 下图说明了ident 协议是如何工作的。 在下图a 中, 客户端打开了一条 HTTP 连接。 然后, 服务器打开自己到客户端 ident 服务器端口(113) 的连接, 发送一条简单的请求, 询问与(由客户端和服务器端口号指定的) 新连接相对应的用户名, 并从客户端解析出包含用户名的响应

image

ident 在组织内部可以很好地工作, 但出于多种原因, 在公共因特网上并不能很好地工作, 原因包括:

  • 很多客户端 PC 没有运行 ident 识别协议守护进程软件;
  • ident 协议会使 HTTP 事务处理产生严重的时延;
  • 很多防火墙不允许 ident 流量进入;
  • ident 协议不安全, 容易被伪造;
  • ident 协议也不支持虚拟 IP 地址;
  • 暴露客户端的用户名还涉及隐私问题。

可以通过 Apache 的 IdentityCheck on 指令告知 Apache Web 服务器使用 ident 查找功能。 如果没有 ident 信息可用, Apache 会用连字符(-) 来填充 ident 日志字段。由于没有 ident 信息可用, 在使用通用日志格式的日志文件中, 第二个字段通常都是连字符

第二步——接收请求报文

连接上有数据到达时, Web 服务器会从网络连接中读取数据, 并将请求报文中的内容解析出来

解析请求报文时, Web 服务器会:

  • 解析请求行, 查找请求方法、 指定的资源标识符(URI) 以及版本号, 各项之间由一个空格分隔, 并以一个回车换行(CRLF) 序列作为行的结束;
  • 读取以 CRLF 结尾的报文首部;
  • 检测到以 CRLF 结尾的、 标识首部结束的空行(如果有的话) ;
  • 如果有的话(长度由 Content-Length 首部指定), 读取请求主体。

image(从连接中读取请求报文)

解析请求报文时, Web 服务器会不定期地从网络上接收输入数据。 网络连接可能随时都会出现延迟。 Web 服务器需要从网络中读取数据, 将部分报文数据临时存储在内存中, 直到收到足以进行解析的数据并理解其意义为止。

报文的内部表示法

有些 Web 服务器还会用便于进行报文操作的内部数据结构来存储请求报文。 比如,数据结构中可能包含有指向请求报文中各个片段的指针及其长度, 这样就可以将这些首部存放在一个快速查询表中, 以便快速访问特定首部的具体值了(参考下图)
image (将请求报文解析为便捷的内部表示形式)

连接的输入/输出处理结构

高性能的 Web 服务器能够同时支持数千条连接。 这些连接使得服务器可以与世界各地的客户端进行通信, 每个客户端都向服务器打开了一条或多条连接。 某些连接可能在快速地向 Web 服务器发送请求, 而其他一些连接则可能在慢慢发送, 或者不经常发送请求, 还有一些可能是空闲的, 安静地等待着将来可能出现的动作。

因为请求可能会在任意时刻到达, 所以 Web 服务器会不停地观察有无新的 Web 请求。 不同的 Web 服务器结构会以不同的方式为请求服务, 如图所示

  • 单线程 Web 服务器(参见图a)
    单线程的 Web 服务器一次只处理一个请求, 直到其完成为止。 一个事务处理结束之后, 才去处理下一条连接。 这种结构易于实现, 但在处理过程中, 所有其他连接都会被忽略。 这样会造成严重的性能问题, 只适用于低负荷的服务器, 以及type-o-serve 这样的诊断工具

  • 多进程及多线程 Web 服务器(参见图b)
    多进程和多线程 Web 服务器用多个进程,或更高效的线程同时对请求进行处理。可以根据需要创建, 或者预先创建一些线程 / 进程。 6 有些服务器会为每条连接分配一个线程 / 进程, 但当服务器同时要处理成百、 上千, 甚至数以万计的连接时,需要的进程或线程数量可能会消耗太多的内存或系统资源。 因此, 很多多线程 Web 服务器都会对线程 / 进程的最大数量进行限制

  • 复用 I/O 的服务器(参见图c)
    为了支持大量的连接, 很多 Web 服务器都采用了复用结构。 在复用结构中, 要同时监视所有连接上的活动。 当连接的状态发生变化时(比如, 有数据可用, 或出现错误时), 就对那条连接进行少量的处理; 处理结束之后, 将连接返回到开放连接列表中, 等待下一次状态变化。 只有在有事情可做时才会对连接进行处理; 在空闲连接上等待的时候并不会绑定线程和进程

  • 复用的多线程 Web 服务器(参见图d)
    有些系统会将多线程和复用功能结合在一起, 以利用计算机平台上的多个 CPU。多个线程(通常是一个物理处理器) 中的每一个都在观察打开的连接(或打开的连接中的一个子集), 并对每条连接执行少量的任务

image

第三步——处理请求

一旦 Web 服务器收到了请求, 就可以根据方法、 资源、 首部和可选的主体部分来对请求进行处理了。

有些方法(比如 POST) 要求请求报文中必须带有实体主体部分的数据。 其他一些方法(比如 OPTIONS) 允许有请求的主体部分, 也允许没有。 少数方法(比如GET) 禁止在请求报文中包含实体的主体数据

第四步——对资源的映射及访问

Web 服务器是资源服务器。 它们负责发送预先创建好的内容, 比如 HTML 页面或JPEG 图片, 以及运行在服务器上的资源生成程序所产生的动态内容。

在 Web 服务器将内容传送给客户端之前, 要将请求报文中的 URI 映射为 Web 服务器上适当的内容或内容生成器, 以识别出内容的源头

docroot文档根目录

Web 服务器支持各种不同类型的资源映射, 但最简单的资源映射形式就是用请求URI 作为名字来访问 Web 服务器文件系统中的文件。 通常, Web 服务器的文件系统中会有一个特殊的文件夹专门用于存放 Web 内容。 这个文件夹被称为文档的根目录(document root, 或 docroot)。 Web 服务器从请求报文中获取 URI, 并将其附加在文档根目录的后面

在图中, 有一条对 /specials/saw-blade.gif 的请求到达。 这个例子中 Web 服务器的文档根目录为 /usr/local/httpd/files。 Web 服务器会返回文件 /usr/local/httpd/files/specials/saw-blade.gif。

image (将请求 URI 映射为本地 Web 服务器上的资源)

在配置文件 httpd.conf 中添加一个 DocumentRoot 行就可以为 Apache Web 服务器设置文档的根目录了:

DocumentRoot /usr/local/httpd/files

服务器要注意, 不能让相对 URL 退到 docroot 之外, 将文件系统的其余部分暴露出来。 比如, 大多数成熟的 Web 服务器都不允许这样的 URI 看到 Joe 的五金商店文档根目录上一级的文件:

http://www.joes-hardware.com/../

虚拟托管的docroot

虚拟托管的 Web 服务器会在同一台 Web 服务器上提供多个 Web 站点, 每个站点在服务器上都有自己独有的文档根目录。 虚拟托管 Web 服务器会根据 URI 或 Host 首部的 IP 地址或主机名来识别要使用的正确文档根目录。 通过这种方式, 即使请求URI 完全相同, 托管在同一 Web 服务器上的两个 Web 站点也可以拥有完全不同的内容了

图 5-9 中的服务器托管了两个站点: www.joes-hardware.comwww.marys-antiques.com。 服务器可以通过 HTTP 的 Host 首部, 或根据不同的 IP 地址来区分不同的Web 站点

  • 当请求 A 到达时, 服务器会获取文件 /docs/joe/index.html。
  • 当请求 B 到达时, 服务器会获取文件 /docs/mary/index.html。

image(虚拟托管的请求会使用不同的文档根目录)

用户的主目录docroot

Docroot 的另一种常见应用是在 Web 服务器上为人们提供私有的 Web 站点。 通常会把那些以斜杠和波浪号(/~) 开始, 后面跟着用户名的 URI 映射为此用户的私有文档根目录。 私有 docroot 通常都是用户主目录下那个名为 public_html 的目录, 但也可将其配置为其他值(参见图)。

image (不同用户有不同的 docroot)

目录列表

Web 服务器可以接收对目录 URL 的请求, 其路径可以解析为一个目录, 而不是文件。 我们可以对大多数 Web 服务器进行配置, 使其在客户端请求目录 URL 时采取不同的动作。

  • 返回一个错误。
  • 不返回目录, 返回一个特殊的默认“索引文件”。
  • 扫描目录, 返回一个包含目录内容的 HTML 页面。

大多数 Web 服务器都会去查找目录中一个名为 index.html 或 index.htm 的文件来代表此目录。 如果用户请求的是一个目录的 URL, 而且这个目录中有一个名为 index.html(或 index.htm) 的文件, 服务器就会返回那个文件的内容。

在 Apache Web 服务器上, 可以用配置指令 DirectoryIndex 来配置要作为默认目录文件使用的文件名集合。 指令 DirectoryIndex 会按照优先顺序列出所有可以作为目录索引文件使用的文件名。 下列配置行会使 Apache 在收到一个目录 URL 请求时, 在目录中搜索命令中列出来的任意一个文件:

DirectoryIndex index.html index.htm home.html home.htm index.cgi

如果用户请求目录 URI 时, 没有提供默认的索引文件, 而且没有禁止使用目录索
引, 很多 Web 服务器都会自动返回一个 HTML 文件, 此文件中会列出那个目录里的文件名, 以及每个文件的大小和修改日期, 还包括到每个文件的 URI 链接。 使用这个文件列表可能会很方便, 但有些好事者也可以通过它在 Web 服务器上找到一些通常找不到的东西。

可以通过以下 Apache 指令禁止自动生成目录索引文件:

Options -Indexes

动态内容资源的映射

Web 服务器还可以将 URI 映射为动态资源——也就是说, 映射到按需动态生成内容的程序上去(参见图)。 实际上, 有一大类名为应用程序服务器的 Web 服务器会将 Web 服务器连接到复杂的后端应用程序上去。 Web 服务器要能够分辨出资源什么时候是动态的, 动态内容生成程序位于何处, 以及如何运行那个程序。 大多数Web 服务器都提供了一些基本的机制以识别和映射动态资源
image(Web 服务器可以提供静态资源和动态资源)

Apache 允许用户将 URI 路径名组件映射为可执行文件目录。 服务器收到一条带有可执行路径组件的对 URI 的请求时, 会试着去执行相应服务器目录中的程序。
例如, 下列 Apache 配置指令就表明所有路径以 /cgi-bin/ 开头的 URI 都应该执行在目录 /usr/local/etc/httpd/cgi-programs/ 中找到的相应文件:

ScriptAlias /cgi-bin/ /usr/local/etc/httpd/cgi-programs/

Apache 还允许用户用一个特殊的文件扩展名来标识可执行文件。 通过这种方式就可以将可执行脚本放在任意目录中了。 下面的 Apache 配置指令说明要执行所有以 .cgi结尾的 Web 资源:

AddHandler cgi-script .cgi

CGI 是早期出现的一种简单、 流行的服务端应用程序执行接口。 现代的应用程序服务器都有更强大更有效的服务端动态内容支持机制, 包括微软的动态服务器页面(Active Server Page) 和 Java servlet。

服务器端包含项

很多 Web 服务器还提供了对服务器端包含项(SSI) 的支持。 如果某个资源被标识为存在服务器端包含项, 服务器就会在将其发送给客户端之前对资源内容进行处理。

要对内容进行扫描, 以查找(通常包含在特定 HTML 注释中的) 特定的模板, 这些模板可以是变量名, 也可以是嵌入式脚本。 可以用变量的值或可执行脚本的输出来取代特定的模板。 这是创建动态内容的一种简便方式。

访问控制

Web 服务器还可以为特定资源进行访问控制。 有请求到达, 要访问受控资源时,Web 服务器可以根据客户端的 IP 地址进行访问控制, 也可以要求输入密码来访问资源

第五步——构建响应

一旦 Web 服务器识别出了资源, 就执行请求方法中描述的动作, 并返回响应报文。响应报文中包含有响应状态码、 响应首部, 如果生成了响应主体的话, 还包括响应主体

响应实体

如果事务处理产生了响应主体, 就将内容放在响应报文中回送过去。 如果有响应主体的话, 响应报文中通常包括:

  • 描述了响应主体 MIME 类型的 Content-Type 首部;
  • 描述了响应主体长度的 Content-Length 首部;
  • 实际报文的主体内容。

MIME类型

Web 服务器要负责确定响应主体的 MIME 类型。 有很多配置服务器的方法可以将MIME 类型与资源关联起来。

  • MIME 类型(mime.types)
    Web 服务器可以用文件的扩展名来说明 MIME 类型。 Web 服务器会为每个资源扫描一个包含了所有扩展名的 MIME 类型的文件, 以确定其 MIME 类型。 这种基于扩展名的类型相关是最常见的, 参见图

image (Web 服务器用 MIME 类型文件来设置资源输出的 Content-type 首部)

  • 魔法分类(Magic typing)
    Apache Web 服务器可以扫描每个资源的内容, 并将其与一个已知模式表(被称为魔法文件) 进行匹配, 以决定每个文件的 MIME 类型。 这样做可能比较慢,但很方便, 尤其是文件没有标准扩展名的时候。

  • 显式分类(Explicit typing)
    可以对 Web 服务器进行配置, 使其不考虑文件的扩展名或内容, 强制特定文件或目录内容拥有某个 MIME 类型

  • 类型协商
    有些 Web 服务器经过配置, 可以以多种文档格式来存储资源。 在这种情况下,可以配置 Web 服务器, 使其可以通过与用户的协商来决定使用哪种格式(及相关的 MIME 类型)“最好”

重定向

Web 服务器有时会返回重定向响应而不是成功的报文。 Web 服务器可以将浏览器重定向到其他地方来执行请求。 重定向响应由返回码 3XX 说明。 Location 响应首部包含了内容的新地址或优选地址的 URI。
重定向可用于下列情况。

  • 永久搬离的资源
    资源可能已经被移动到了新的位置, 或者被重新命名, 有了一个新的 URL。 Web 服务器可以告诉客户端资源已经被重命名了,这样客户端就可以在从新地址获取资源之前, 更新书签之类的信息了。 状态码 301 Moved Permanently 就用于此类重定向。
  • 临时搬离的资源
    如果资源被临时移走或重命名了, 服务器可能希望将客户端重定向到新的位置上去。 但由于重命名是临时的, 所以服务器希望客户端将来还可以回头去使用老的URL, 不要对书签进行更新。 状态码 303 See Other 以及状态码 307 TemporaryRedirect 就用于此类重定向。
  • URL 增强
    服务器通常用重定向来重写 URL, 往往用于嵌入上下文。 当请求到达时, 服务器会生成一个新的包含了嵌入式状态信息的 URL, 并将用户重定向到这个新的URL 上去。 7 客户端会跟随这个重定向信息, 重新发起请求, 但这次的请求会包含完整的、 经过状态增强的 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 服务器会在日志文件中添加一个条目, 来描述已执行的事务。 大多数 Web 服务器都提供了几种日志配置格式

  • 3
    点赞
  • 25
    收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:酷酷鲨 设计师:CSDN官方博客 返回首页
评论 1

打赏作者

「已注销」

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值