HTTP服务器原理之CGI协议

Posted by WGrape的博客 on October 11, 2019

文章内容更新请以 WGrape GitHub博客 : HTTP服务器原理之CGI协议 为准

前言

本文原创,著作权归WGrape所有,未经授权,严禁转载

预备

  1. HTTP服务器 又称 Web服务器,是最常用的协议服务器之一。
  2. 常见的协议服务器主要有 : HTTP协议服务器、TCP协议/UDP协议服务器、Websocket协议服务器、FTP协议服务器
  3. CGI 是HTTP服务器独有的协议,只有HTTP服务器需要遵循 CGI 协议,其他的TCP等协议服务器则没有CGI之类的协议。
  4. CGI 程序是最难让人理解的一个东西,其不是表示一个具体的东西,而是一个概念,表示专门用于处理请求的处理程序。即 CGI 程序 本质上就只是一个 处理程序 ,专门用于处理请求。
  5. 因为 CGI 协议中所定义规范的 CGI程序 就只是一个处理请求的程序而已,可能 CGI协议 本身都没想好 CGI 程序中到底需要有什么语言级别的解析模块。
  6. 因此我们不用管 CGI 程序 到底是什么语言编写 ,CGI 程序 到底是由什么组成 ,其内部都包含什么解析编译等语言引擎级别的东西。因为 CGI 协议中所定义规范的 CGI程序 就只是一个处理请求的程序而已

CGI RFC

对 CGI 的几乎一切疑问,通过阅读 CGI 的 RFC 都即可解决。CGI RFC 地址

原理

CGI 协议

image

  1. 在左边实现 CGI 协议 的程序叫做 :Server 服务器
  2. 在右边实现 CGI 协议 的程序叫做 :CGI 程序,或者就简单的把它理解为 处理请求的 处理程序
  3. Script 等同于 CGI程序,都是 CGI协议 规定的 处理程序,二者是一个概念。
  4. CGI 程序并不是某个具体的东西,而是一个概念,一个表示 用来处理请求 的 处理程序 模型
  5. 在 Server 中通过 注入 Module 模块 的方法,实现了服务器与处理程序的解耦

CGI 协议实现

image

  1. CGI 协议规定了 CGI程序(处理程序) 在收到请求时,通过 fork-and-execute 来实现对不同请求的处理,这也正是 CGI 协议的缺点 :在并发时会严重消耗资源甚至崩溃
  2. 每一个 PHP-CGI 程序都只是一个 CGI 程序,前缀 PHP 只是表示 其为用 PHP 编写的 处理程序 。

FastCGI 协议

为了弥补 CGI 协议的不足,FastCGI协议应运而生,其大体与 CGI 协议的结构图一样,主要不同的是:FastCGI协议 要求 处理程序使用 Master-worker 模式,不再推荐使用 fork-and-execute 模式。

image

  1. FPM 即 FastCGI Process Manager
  2. 前面说了 CGI 程序是处理程序,那么 FPM 就是 处理程序的 管理程序 。FPM 就是专门用于管理 CGI 的一个程序
  3. 同 CGI 程序一样 ,FPM 程序 也只是一个概念,一个模型而已 :用于描述 管理处理程序 的程序

FastCGI 协议实现

image

  1. PHP-FPM 前缀 PHP 同样也只是表示 用 PHP 实现的 FPM 。
  2. PHP-FPM 会在第一次启动的时候,启动一个 master 主进程,并维护 worker 进程池,每一个worker进程都是用于处理请求的 CGI 程序 (处理程序)

Nginx配置PHP FastCGI

配置Nginx的时候能发现总是需要配置一个upstream的东西,它就是PHP的一个fastCGI程序,它会和Nginx通信。Nginx把请求到的信息,转发调用起PHP fatcgi程序,这样调接口的时候 ,就运行起了一个PHP请求进程、

upstream vault {
    server 127.0.0.1:8001;
}

server {
    listen 80;
    server_name vault.shopshop.space;

    error_log /var/log/nginx/vault.shopshop.space_error.log;
    access_log /var/log/nginx/vault.shopshop.space_access.log;

    root /path/to/public;
    index index.php;

    location / {
        try_files $uri /index.php$is_args$args;
     }

    location ~ \.php {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param SCRIPT_NAME $fastcgi_script_name;
        fastcgi_index index.php;
        fastcgi_pass vault;
    }
}