[后台开发] 公共网关接口(Common Gateway Interface, CGI)简介

陪她去流浪 桃子 2019年06月06日 阅读次数:3476

这篇文章简要地介绍一下古老的 CGI(Common Gateway Interface,公共网关接口)。

静态文件服务

在互联网的早期一个时期,那时候的 WWW 网页服务还只是简单的静态页面服务。它的工作过程是这样的:

  • 浏览器向服务器发起文件请求,比如:GET /a.txt
  • 服务器找到a.txt文件
  • 服务器读取文件内容
  • 服务器返回内容给浏览器
  • 浏览器展示返回的内容

就像下面这张图描绘的那样:

静态文件请求.svg

动态内容服务

不过,人们很快就觉得,直接返回文件内容的方式太单调了,因为内容完全是固定不变的,不能动态地生成内容,看到不同的页面。 所以,如果想要每次的请求内容都不一样(比如:显示当前时间,显示登陆者的用户名),怎么办? 很简单,人们马上就想到了新的办法。

当服务器接收到浏览器的请求时,把请求的路径当成一个可执行文件,执行它,并把可执行文件的标准输出返回给浏览器。

它的工作过程是这样的:

  • 浏览器向服务器发起一个请求,比如:GET /cgi-bin/echo
  • 服务器找到/cgi-bin/echo这个可执行文件
  • 服务器把请求路径,HTTP头部等值作为环境变量传递给可执行文件
  • 服务器把HTTP请求BODY作为标准输出传递给可执行文件
  • 服务器执行可执行文件
  • 可执行文件执行内部逻辑并把输出写入标准输出,然后退出
  • 服务器读取可执行文件的标准输出
  • 服务器把标准输出返回给浏览器
  • 浏览器展示返回的内容

就像下面这张图描绘的那样:

CGI脚本.svg

由于可执行文件拥有自己的逻辑,所以它可以输出任意的内容。而不像静态文件那样,内容永远是固定不变的。这样一样,浏览器就可以看到动态的内容了。

我们通常把由静态文件生成的网页叫作静态网站,而把后端可执行文件动态生成的网页叫作动态网站

后端的这个可执行文件通常叫作网关程序。而服务器与网关程序之间的这个通信协议,叫作公共网关接口(Common Gateway Interface, CGI)

关于HTTP请求路径

先说点题外话。

几年前我用 C++ 写过一个 HTTP Web 服务器(这里),它也简单地支持CGI,(实现代码),包含但不限于常见的 lua、php。

它甚至支持把 Windows 的批处理脚本文件(.bat文件)、可执行文件(.exe文件)也当成网关程序来使用:

if(std::regex_match(uri, matches, std::regex(R"(/cgi-bin/([^/]+\.bat))", std::regex_constants::icase))) {
            auto script = file_system::exe_dir() + '/' + matches[1].str();
            auto command_line = '"' + script + '"';

            ssmap_t env;

            exec(command_line, env, [&](const char* buf, int size) {
                send(buf, size);
            });
            
            close();

            return true;
}

实现这个功能,它至少改变了我对HTTP的一些“习惯性”的错误看法。那就是:

HTTP的服务器对请求路径拥有完全的解释权,跟请求的路径并没有绝对的关系。

什么意思?比如我发起一个GET /a.txt的请求,很多人会认为它是打开一个TXT文件;发起一个GET /b.exe,也会认为是下载一个程序文件。不会是执行,浏览器怎么可能执行EXE文件?

所以,其实并不是那样。有很多人这里都有误解,至少我当年是这样。

那么怎样决定呢?有很多方式,也不是都靠谱。多数时候,靠 HTTP 的 Content-Type 来猜测是靠谱的。

就是这样。

关于CGI的性能

对于现在的后端开发来说,纯使用CGI作为后端已经极其少见了。因为它有很多比较致命的不足:

  • 对于每一个请求都要新启动一个进程来处理请求

    新启动一个进程对操作系统来说开销特别大,必然造成性能不好。对于服务器的性能,一个简单的比较:同步 < 多进程 < 多线程 < 异步。

  • 进程处理完请求就立即退出

    立即退出意味着请求与请求之间很难产生联系,连简单的数据共享都做不到。所以后来出现了FastCGI,进程不用退出了。

所以,后来的服务器就不怎么再支持CGI了。比如 nginx。

参考

标签:HTTP · nginx · CGI