Python Web框架、WSGI和CGI是如何配合使用的

156

我有一个Bluehost账户,可以在其中运行Python脚本作为CGI。我猜这是最简单的CGI,因为我需要在.htaccess中定义以下内容才能运行:

Options +ExecCGI
AddType text/html py
AddHandler cgi-script .py

现在,每当我搜索使用Python进行Web编程时,我经常听到很多关于WSGI以及大多数框架如何使用它的内容。但是我不理解它们是如何结合在一起的,特别是当我的Web服务器已经给定(在主机上运行的Apache),而我无法真正操作它(除了定义.htaccess命令)。 WSGI、CGI和框架之间有什么联系?如果我想在基本的CGI配置上运行Web框架(例如web.pyCherryPy),我需要知道、安装和做什么?如何安装WSGI支持?
5个回答

256

WSGI、CGI和框架之间有什么联系?

Apache侦听80端口,它接收到HTTP请求后解析请求,以找到响应的方法。Apache有很多响应方式,一种响应方式是使用CGI运行脚本,另一种则是简单地提供文件。

在CGI的情况下,Apache通过CGI协议准备一个环境并调用脚本。这是标准的Unix Fork/Exec进程 -- CGI子进程继承操作系统的环境,包括套接字和stdout。CGI子进程写入响应,响应返回给Apache,然后将响应发送到浏览器。

CGI较为原始且繁琐,主要是因为它为每个请求分叉出一个子进程,子进程必须退出或关闭stdout和stderr来表示响应结束。

WSGI是基于CGI设计模式的接口,但不一定是CGI,它不必为每个请求分叉一个子进程。

WSGI通过几个重要方面增强了CGI设计模式。它会为您解析HTTP请求头并将其添加到环境中。它会将任何POST相关的输入作为类似文件的对象提供给环境。它还会为您提供一个函数来制定响应,从而节省了许多格式化细节。

如果我想在我的基本CGI配置上运行Web框架(如web.py或cherrypy),我需要知道/安装/做什么?

请记住,每次分叉子进程都是昂贵的。有两种方式来避免这个问题。

  1. 内嵌 mod_wsgimod_python嵌入Python到Apache中,不会进行进程分叉,Apache直接运行Django应用程序。

  2. 守护进程 mod_wsgimod_fastcgi 允许Apache与一个单独的守护进程(或“长时间运行的进程”)交互,使用WSGI协议。你启动长时间运行的Django进程,然后配置Apache的mod_fastcgi与此进程通信。

请注意,mod_wsgi可以在嵌入模式或守护进程模式下工作。

当你阅读有关mod_fastcgi的内容时,你会发现Django使用flup从mod_fastcgi提供的信息创建WSGI兼容的接口。这个流程类似于:

Apache -> mod_fastcgi -> FLUP (via FastCGI protocol) -> Django (via WSGI protocol)
Django有几个"django.core.handlers"来处理各种接口。
对于mod_fastcgi,Django提供了一个manage.py runfcgi来集成FLUP和处理程序。
对于mod_wsgi,这里有一个核心处理程序。
如何安装WSGI支持?
请按照这些说明操作。 https://code.google.com/archive/p/modwsgi/wikis/IntegrationWithDjango.wiki 有关背景,请参见此处 http://docs.djangoproject.com/en/dev/howto/deployment/#howto-deployment-index

4
由于我在共享托管上,因此无法安装mod_wsgi模块。 我只有fcgi支持。 那么,我该如何通过fcgi运行WSGI应用程序? - Eli Bendersky
3
+1 那是一个很好的答案,回答了我大部分但不是所有的问题。这个答案仍然不完整。你解释了CGI和WSGI,但FASTCGI和WSGI之间有什么关系和区别呢?哪个更好?它们如何工作?mod_python又是如何涉及的? 这是一个优秀的回答,解释了CGI和WSGI,但FASTCGI和WSGI之间有什么关系和区别呢?FASTCGI是一种改进的CGI协议,旨在提高CGI的性能和效率。与标准CGI不同,它允许长连接,即可以在多个HTTP请求之间保持连接,从而避免了每个请求都要重新启动进程的开销。WSGI是Python Web应用程序和Web服务器之间的通用接口,在Python Web框架中被广泛使用。它提供了一套统一的规范,使得不同的Web框架和Web服务器可以互相兼容。WSGI与FASTCGI不直接相关,因为WSGI是一种Python特定的协议,而FASTCGI是一种常见的Web服务器协议。虽然它们都可以用于加速Web应用程序,但是它们的实现方式和优缺点都不同,没有绝对的最佳选择。至于mod_python,它是一种将Python代码嵌入到Apache Web服务器中的模块。它允许直接将Python代码作为Apache模块运行,从而提高了性能和可靠性。然而,由于mod_python在多线程环境下存在问题,并且难以与其他Web框架集成,因此现在已经不再推荐使用。 - claws
14
S.Lott,与其抱怨人们询问哪个更好,为什么不直接说“mod_wsgi在X方面更好,fastcgi在Y方面更好”,如果提问者有更具体的问题,他们会进一步询问。 - Gregg Lind
8
@Greg Lind: 为什么不直接说 "mod_wsgi 对于 X 更好,fastcgi 对于 Y 更好" 呢?因为这并不容易。X 和 Y 集合中有数十个非功能性质量因素的元素,很难将它们全部列举出来。最好让人们就相关的质量因素提出具体问题。 - S.Lott
5
请注意:自版本1.7起,runfcgi选项已不推荐使用,并且在Django 1.9中移除了FastCGI支持。 - OBu
显示剩余3条评论

64
我认为Florian's answer回答了你关于"什么是WSGI"的问题,特别是如果你阅读了the PEP
至于你在最后提出的问题:
WSGI、CGI、FastCGI等都是用于Web服务器运行代码并传递生成的动态内容的协议。与静态Web服务相比,其中纯HTML文件基本上按原样传递给客户端。
CGI、FastCGI和SCGI都是与语言无关的。您可以使用Perl、Python、C、bash或其他语言编写CGI脚本。CGI定义了将调用哪个可执行文件,基于URL以及如何调用它:参数和环境。它还定义了在您的可执行文件完成后应该如何将返回值传回Web服务器。这些变化基本上是为了能够处理更多请求、减少延迟等优化;基本概念是相同的。
WSGI仅适用于Python。它定义了标准函数签名,而不是与语言无关的协议:
def simple_app(environ, start_response):
    """Simplest possible application object"""
    status = '200 OK'
    response_headers = [('Content-type','text/plain')]
    start_response(status, response_headers)
    return ['Hello world!\n']

那是一个完整的(虽然有限)WSGI应用程序。具有WSGI支持的Web服务器(例如使用mod_wsgi的Apache)可以在每个请求到达时调用此函数。
这样做的原因是我们可以避免将HTTP GET / POST转换为CGI再转换回Python,然后再返回,从而避免混乱的步骤。它是一种更直接、更清洁和更高效的链接方式。
如果所有需要为请求执行的操作都是函数调用,则可以更轻松地在Web服务器后面运行长时间运行的框架。对于普通的CGI,您需要为每个单独的请求启动整个框架
要拥有WSGI支持,您需要安装WSGI模块(如mod_wsgi),或者使用内置WSGI的Web服务器(如CherryPy)。如果两者都不可能,您可以使用PEP中提供的CGI-WSGI桥接器。

4
让WSGI不具备语言通用性是谁的愚蠢想法?这样做有什么意义呢?与其这样,还不如将整个Python作为Apache模块一起发布。 - salmatron
2
@SalmanPK 我认为这只是一个权衡。毫无疑问,制定一种与语言无关的协议,并通过在所选语言中实现函数来使用它并不容易(如果不是不可能的话)。 - phunehehe
但是FastCGI也没有每个请求都重新启动应用程序的限制。 - undefined

22

您可以像Pep333所示的那样在CGI上运行WSGI作为示例。但是,每次有请求时都会启动一个新的Python解释器,并且需要构建整个上下文(数据库连接等),这需要花费时间。

如果您想要运行WSGI,最好的方法是您的主机安装mod_wsgi并进行适当的配置,以将控制权转移到您的应用程序。

Flup是另一种使用WSGI的方式,可用于任何能够使用FCGISCGI或AJP的Web服务器。从我的经验来看,只有FCGI真正起作用,它可以通过mod_fastcgi或者如果您可以运行一个单独的Python守护进程,则可以通过mod_proxy_fcgi在Apache中使用。

WSGI是一种协议,类似于CGI,它定义了Web服务器和Python代码之间交互的一组规则,它被定义为Pep333。它使许多不同的Web服务器可以使用许多不同的框架和应用程序,使用相同的应用程序协议。这非常有益,并使其非常有用。


4
运行WSGI在CGI上,这就是"flup"的作用吗?flup与计划方案有什么关联? - Eli Bendersky

9
如果你对这个领域中的所有术语感到不清楚,那么可以看一下一份官方的Python HOWTO文档,它涵盖了CGI、FastCGI、WSGI等,并能给你一个很好的背景了解。链接:http://docs.python.org/howto/webservers.html

5
链接已过时,我认为这是更新后的链接:https://docs.python.org/2.7/howto/webservers.html - Stefaan
很棒的材料 :) 除了被接受的答案,还应该阅读官方介绍。 - Rick

6
这是Python的一个简单抽象层,类似于Servlet规范适用于Java。而CGI真的很低级,只是将一些东西转储到进程环境和标准输入/输出中,上述两个规范将HTTP请求和响应建模为语言中的构造。然而,我的印象是,在Python中,人们还没有完全确定事实上的实现方式,因此您会看到参考实现和其他提供WSGI支持的实用程序类型库的混合(例如Paste)。当然,我可能错了,我是Python的新手。 “Web脚本”社区从不同方向(共享托管,CGI遗留问题,特权分离问题)解决这个问题,而Java的人们则有幸从静态编译和部署代码的专用环境中运行单个企业容器开始。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接