项目

通用

个人资料

操作

HowToPythonWSGI

背景:什么是WSGI?

官方WSGI文档(http://wsgi.readthedocs.io/en/latest/)在以下网址对WSGI进行了定义:
http://wsgi.readthedocs.io/en/latest/what.html

WSGI是Web服务器网关接口。它是一个规范,描述了Web服务器如何与Web应用程序通信,以及Web应用程序如何串联起来处理一个请求。

如果上面写明WSGI是“一个描述支持Python的Web服务器如何与运行在Python服务器内的Python Web应用程序通信的规范”,那会更清晰。WSGI描述了一个Python API,用于Python解释器运行一个可调用的Python函数(实现一个Web应用程序)来处理请求,以及该Python函数如何响应请求。

如果Web服务器是基于Python的Web服务器或在其内部嵌入了Python解释器,那么Web服务器可以在Web服务器进程中实现WSGI API。否则,Web服务器必须使用不同的网关协议(HTTP、CGI、FastCGI、SCGI、uwsgi等)与Python进程(支持相同网关协议的进程)进行通信,然后Python进程可以将请求从网关协议转换为WSGI API。

lighttpd和Python WSGI

lighttpd是单线程的,并且不打算在lighttpd服务器中嵌入Python解释器,因为任意的Python应用程序代码可能导致整个lighttpd服务器阻塞。因此,lighttpd必须使用另一种网关协议来运行实现WSGI API的Python应用程序。
  • uwsgi:lighttpd可以使用mod_scgi通过uwsgi连接到Python服务器(scgi.protocol = "uwsgi"(lighttpd 1.4.42起))
  • SCGI:lighttpd可以使用mod_scgi通过SCGI连接到Python服务器(scgi.protocol = "scgi"(默认))
  • FastCGI:lighttpd可以使用mod_fastcgi通过FastCGI连接到Python服务器
  • HTTP:lighttpd可以使用mod_proxy通过HTTP连接到Python服务器
  • CGI:lighttpd可以使用mod_cgi通过CGI启动Python程序

Python服务器必须作为独立进程运行,以服务Python WSGI应用程序(除非lighttpd配置为将Python进程作为CGI运行)。有许多Python服务器支持上述一种或多种协议,并且也支持Python WSGI应用程序。WSGI网站列出了一些Python服务器,网址为http://wsgi.readthedocs.io/en/latest/servers.html

选项众多,为了帮助新的Python WSGI应用程序开发者入门,下面将描述一些简单易用的选项。

在继续之前,请参阅
https://docs.pythonlang.cn/3/howto/webservers.html “如何在Web中使用Python”(如果您不熟悉Web应用程序的编写)。

示例

通过CGI运行Python WSGI应用程序

CGI通常是运行Python WSGI应用程序最慢的方式,但通常也是最容易设置的方式之一。Python 2.5或更高版本的标准库随附wsgiref(https://docs.pythonlang.cn/3/library/wsgiref.html)。这是一个基本的“Hello World!” Python WSGI应用程序,由wsgiref CGIHandler运行。它可以放入文件中,标记为可执行,并由Web服务器作为CGI程序运行,例如使用mod_cgi

#!/usr/bin/env python
import wsgiref.handlers

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/plain;charset=utf-8')])
    return ['Hello World!\n']

if __name__ == '__main__':
    wsgiref.handlers.CGIHandler().run(application)

关于上述内容更详细的解释可在http://henry.precheur.org/python/how_to_serve_cgi.html找到

通过HTTP运行Python WSGI应用程序

另一种运行Python WSGI应用程序的方式是在接受HTTP请求的Python服务器中。有许多基于Python的Web服务器,它们具有不同的功能和性能特点,但为了简单起见,Python 2.5或更高版本的标准库提供了wsgiref.simple_server(https://docs.pythonlang.cn/3/library/wsgiref.html#module-wsgiref.simple_server)。尽管基于Python的Web服务器可能能够服务Web站点的所有客户端HTTP请求,但通常会有一个功能丰富的Web服务器处理静态内容、身份验证等,它位于专注于处理Python WSGI应用程序的基于Python的Web服务器前面。lighttpd可以服务各种客户端请求,并且可以配置为使用mod_proxy将特定客户端请求发送到后端基于Python的Web服务器,当这些客户端请求应由Python WSGI应用程序处理时。

https://docs.pythonlang.cn/3/library/wsgiref.html#examples中给出的示例

#!/usr/bin/env python
from wsgiref.simple_server import make_server

# Every WSGI application must have an application object - a callable
# object that accepts two arguments. For that purpose, we're going to
# use a function (note that you're not limited to a function, you can
# use a class for example). The first argument passed to the function
# is a dictionary containing CGI-style environment variables and the
# second variable is the callable object (see PEP 333).
def hello_world_app(environ, start_response):
    status = '200 OK'  # HTTP Status
    headers = [('Content-Type', 'text/plain;charset=utf-8')]  # HTTP Headers
    start_response(status, headers)

    # The returned object is going to be printed
    return [b"Hello World"]

httpd = make_server('', 8000, hello_world_app)
print("Serving on port 8000...")

# Serve until process is killed
httpd.serve_forever()

为了服务客户端请求,启动(和关闭)脚本必须将基于Python的Web服务器作为守护进程启动,就像必须将lighttpd Web服务器作为守护进程启动一样。

使用uWSGI服务器通过uwsgi、SCGI、FastCGI或HTTP运行Python WSGI应用程序

有大量基于Python的服务器支持一种或多种网关协议(例如uwsgi、SCGI、FastCGI、HTTP等)。WSGI网站列出了一些Python服务器,网址为http://wsgi.readthedocs.io/en/latest/servers.html

与通过HTTP服务Python WSGI应用程序(见上文)一样,Python服务器必须作为守护进程启动,与Web服务器守护进程分开,以便通过其他网关协议(包括uwsgi、SCGI和FastCGI)运行Python WSGI应用程序。

对于此示例,我们选择uWSGI服务器来运行一个简单的Python WSGI hello_world_app。首先安装uWSGI服务器
  • Fedora:$ dnf install uwsgi uwsgi-plugin-python3
  • Debian:$ apt-get install uwsgi uwsgi-plugin-python3

在文件/path/to/htdocs/hello_world_app.py中创建一个简单的“Hello World!” Python WSGI应用程序(将/path/to/htdocs/替换为您自己的路径)。

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/plain;charset=utf-8')])
    return ['Hello World!\n']

以下是启动脚本运行uWSGI服务器在localhost的8080端口处理uwsgi协议(小写“uwsgi”)的基本命令

uwsgi -L --uwsgi-socket 127.0.0.1:8080 --plugin python3 --pythonpath /path/to/htdocs -w hello_world_app

有了上述配置,lighttpd可以配置为使用mod_scgi将hello_world_app的请求发送到127.0.0.1:8080。lighttpd 1.4.42或更高版本需要lighttpd.conf scgi.protocol = "uwsgi"来告诉lighttpd使用稍微更高效的uwsgi协议而不是默认的scgi协议。

uWSGI服务器可以使用SCGI协议与lighttpd mod_scgi配合使用,尽管uwsgi协议效率更高。

uwsgi -L --scgi-socket 127.0.0.1:8080 --plugin python3 --pythonpath /path/to/htdocs -w hello_world_app

uWSGI服务器可以使用FastCGI协议与lighttpd mod_fastcgi配合使用。

uwsgi -L --fastcgi-socket 127.0.0.1:8080 --plugin python3 --pythonpath /path/to/htdocs -w hello_world_app

uWSGI服务器可以使用HTTP协议与lighttpd Docs_ModProxy配合使用。

uwsgi -L --http-socket 127.0.0.1:8080 --plugin python3 --pythonpath /path/to/htdocs -w hello_world_app

当然,上述示例中的“/path/to/htdocs”应替换为hello_world_app.py的实际路径。

uWSGI服务器有许多功能来控制内存使用、并行性等。大量uWSGI文档可在http://uwsgi-docs.readthedocs.io/en/latest/获取

附注:为了稍快的性能,lighttpd和uWSGI都可以配置为使用Unix域套接字而不是TCP套接字,例如uwsgi --<xxx>-socket /path/to/yourapplication.sock ...(其中<xxx>是协议,如上例所示)。

使用flipflop服务器通过FastCGI运行Python WSGI应用程序

flipflop服务器可用于运行Python WSGI应用程序,lighttpd使用mod_fastcgi将请求发送到该应用程序。下载flipflop服务器(https://github.com/Kozea/flipflop)(https://pypi.python.org/pypi/flipflop),并在hello_world_app.py旁边创建以下包装脚本hello_world_app.fcgi(来自上述示例)。

#!/usr/bin/env python
from hello_world_app import application
from flipflop import WSGIServer
WSGIServer(application).run()

或者,
#!/usr/bin/env python
#: optional path to your local python site-packages folder
import sys
sys.path.insert(0, '<your_local_path>/lib/python2.6/site-packages')

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/plain;charset=utf-8')])
    return ['Hello World!\n']

if __name__ == '__main__':
    from flipflop import WSGIServer
    WSGIServer(application).run()

配置lighttpd mod_fastcgi以在lighttpd启动时启动脚本,或将脚本添加到您自己的启动脚本中,以便lighttpd可以使用它。

使用flup服务器通过FastCGI或SCGI运行Python WSGI应用程序

flipflop是flup的精简版(https://www.saddi.com/software/flup/)(https://pypi.python.org/pypi/flup/1.0)。flup在使用flup.server.fcgi时提供一个FastCGI到WSGI的服务器。

from hello_world_app import application
from flup.server.fcgi import WSGIServer
WSGIServer(application).run()

flup在使用flup.server.scgi时也可以作为SCGI到WSGI的服务器运行。
from hello_world_app import application
from flup.server.scgi import WSGIServer
WSGIServer(application).run()

要在Python 3中运行flup,需要flup-py3包。或者,pip install flup6

其他参考

Nicholas Piël于2010年3月15日发布了Python WSGI服务器的基准测试。http://nichol.as/benchmark-of-python-web-servers该帖子有一组非常好的配置不同Python WSGI服务器的示例,但请注意,这些基准测试到目前为止已超过6年。

gstrauss大约4年前更新 · 6个修订