最近用 Flask 给以前写的 OpenCV 代码配置一个入口供前端调用,翻文档的时候发现部署服务器和在本地运行与我一开始想的并不太一样。于是花点时间了解并整理了一下,补补基础课。
CGI 是一种服务器和后端可执行程序之间的交互标准,它描述了『如何通过环境变量来传递请求信息』。
最原始的服务器,简单到就是访问文件目录,每次的请求都是请求加载目录下的文件。比如文档放在 /usr/local/apache/htdocs
目录下,访问 http://example.com/index.html 其实就是请求 /usr/local/apache/htdocs/index.html
文件。
CGI 通过服务器脚本(或者二进制文件),扩展了这个基础的『访问过程』。它利用程序的标准输入输出流,完成 HTTP 通信。每次请求的文本以标准输入流的形式进入服务器端的 CGI 程序,创建进程并执行,然后将运行结果通过进程的标准输出流输出作为响应。
比如 /usr/local/apache/htdocs/cgi-bin
是我们的 CGI 目录,当请求了 CGI 目录里的文件的时候(比如访问 http://example.com/cgi-bin/printenv.pl ),服务器并不会返回这个文件,而会运行这个程序,然后将生成的内容返回给客户端。所以理论上,任何有输入输出能力的语言都可以用来写 CGI。
CGI 的工作原理如图:
解释一下,上面图中的 CGI 指的是 CGI 程序。CGI 是一种协议标准,CGI 程序是实现了 CGI 标准的程序,确保输入输出合法,这是两个相关但不同的概念。
CGI 的优点也就是它的作用了。CGI 程序提供了很多静态网页无法实现的功能,比如加载数据、数据运算等等。早期的动态网页基本都是基于 CGI 实现的。
在 CGI 协议下,解析器的反复加载是性能低下的主要原因。每个发送到服务器的请求,都需要经过『启动进程、处理请求、结束进程』三个步骤,所以当访问量增大时,系统资源的开销也会增大,导致服务器性能下降甚至服务中断。
更惨的是,这种『一个请求一个进程』的模式意味着没有『状态』可言,导致很多资源无法复用,比如连接数据库、内存缓存等等。
FastCGI 是 CGI 的增强版本,用于减少 Server 与 CGI 应用之间的交互开销,从而使 Server 可以同时处理更多的请求。
和 CGI 的 fork-and-execute
模式不同的是,FastCGI 以 Daemon
的形式运行,在初始化的时候会启动一个 FastCGI Server
然后长驻内存,处理一系列的请求。
Nginx+FastCGI 的工作流程是这样的:
php
为后缀的文件)分配到指定端口(例如9000端口)来处理。工作原理如图:
上图中的 wrapper
可以理解为用于启动另一个程序的程序,因为 Nginx 本身不支持对外部程序的直接调用或者解析,所以外部程序必须通过 FastCGI 接口来调用。
除了继承 CGI 原有的优点之外, FastCGI 还有以下特点:
WSGI 是 Web 服务器和 Web 应用程序之间的一种简单而通用的接口,最初是为 Python 量身定做。
WSGI 属于接口规范,从层级上来讲要比 CGI/FastCGI 高级。
WSGI 中存在两种角色:接受请求的 Server 和处理请求的 Application,它们底层是通过 FastCGI 沟通的。
WSGI 的工作流程如下:
Server 端从规定的输入中获取 Request 数据,然后把环境变量(environ)和回调函数(start_response)传给 Application 。
Application 会处理请求并通过回调函数将结果返回给 Server。
和 Serve 对应,一个标准的 Application 接受两个参数:
Middleware 是一个比较特殊的存在,它是夹在二者之间的,对于 Server 端而言它是个 Application ,而对于 Application 而言它就是 Server 端。
它可以实现以下功能:
WSGI 将请求的工作通过异步回调进行拆解,可以很方便的在一个线程空间里同时处理多个请求。
另外,方便进行负载均衡和请求转发,不会造成后端应用阻塞。
其他一些相关的名词一起梳理一下:
OK 就是这样。对这方面不是很了解,如果有错误还望及时指出,不胜感激:)
参考文献: