手写WEB服务器-05-动态页面

手写WEB服务器-05-动态页面

1.前言

所谓的动态页面是跟静态页面对应的,前面我们处理http请求时,是直接从服务器本地打开一个文件发送给浏览器了,而动态页面是指,当你请求一个web资源时,web服务器会动态生成一个页面,再发送给客户端浏览器。

本文要探讨的核心,是web服务器如何动态生成了这个页面。

2.例子

以前面我们搭建开发环境时的例子为例。

客户端发起的请求是这样的:

服务器找到的文件是这样的:

实际的php文件内容是这样的:

然而客户端收到的页面内容却是这样的:

在服务端到底发生了什么,才能把一个3行的极简文件变成了641行的复杂文件呢?

这个过程就发生在下面几行代码中:

3.处理过程

首先,从php页面到html的转换涉及到php语言的解析,web服务器自己实现是不现实的。其次,php官方其实是提供这种解析功能的,该功能以独立组件的形式提供,名字叫做phpfpm。

phpfpm以独立进程的形式运行,可接受tcp连接,在编译安装php的时候指定–enable-fpm即可(可以回头看下前面的环境准备篇,里面有具体操作方法)。

phpfpm进程的侦听端口是9000:

既然是个tcp服务器,就需要有通信协议,这个协议就是FASTCGI(这也是前面代码中,我们调用的函数都含有fcgi的原因)。

所以我们要做的就是,收到php页面请求后,将其包装成fcgi协议,通过TCP连接发送给phpfpm进程,phpfpm进程会把这个php页面解释成html文本,将其包装成fcgi协议,通过TCP连接返回给web服务器,web服务器收到这个应答后,解析出html文本,为它加上一个http协议头,发送给客户端浏览器。

下面我们一一来看。

3.1 发起连接

发起连接的过程就是普通tcp协议客户端的过程,没有什么特殊的:

填上我们配置的ip地址和端口,发送即可:

其中ip地址和端口是个配置:

3.2 转发请求

转发请求的过程分4步:

  • 发送开始请求协议的头和体
  • 发送FCGI参数
  • 发送空参数(表示参数发完了)
  • 发送空标准输入(表示标准输入发完了)

其中最核心的过程是第二个,即发送FCGI参数。

FCGI参数包含这几个:

我们实际请求个页面,然后看看这几个参数需要怎么填:

我们以这个地址为例:

浏览器发来的请求:

web服务器转发给phpfpm的参数:

注意到,其中主要包含四个信息:

  • 方法:GET
  • 文件路径:/root/www/index.php
  • 参数:p=1149

phpfpm收到这些信息后,就会打开并解释/root/www/index.php文件,并把参数p=1149传递给他。

phpfpm后台执行php代码后,就会生成html并返回给web服务器。

3.3 转发应答

web服务器向phpfpm发送完请求后,就会调用web_fcgi_recv函数接收并处理来自phpfpm的应答。

fcgi协议整体上也是”头+内容+填充字节”…”头+内容+填充字节”这种形式。整体的处理过程是,先收一个头(8字节),然后查看头中包含的内容长度信息和填充字节长度信息,然后再把这些内容填充字节收进来。

我们要转发给客户端的html数据就包含在上面说的内容部分。

fcgi的应答是分多次发送的,也就是说,我们会收到多个”头+内容+填充字节”这种数据,所以接收的过程得写在循环中。

另外,我们收到的头中,有一个报文类型的信息,可能包括3种:

其中STDOUT说明我们发送fcgi请求没有问题,返回的是正常的html内容;STDERR则表明我们发送的fcgi请求有问题,比如请求的php文件不存在等,返回的是具体的错误信息(文本形式);END则说明phpfpm已经给我们发送了所有的应答信息,可以转发给浏览器了。

具体的转发过程也比较简单:

我们首先像发静态页面那样,先发一个http200应答,然后再从fcgi应答中提取html部分,转发给浏览器即可。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注