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年。