工具
Web 开发
Web 服务
WSGI 学习笔记
WSGI (Web Server Gateway Interface) - WSGI 是一个 Python 标准,在 PEP 3333 中定义。WSGI 定义了 web server 如何与 web 应用通信,以及多个 web 应用如何串联起来处理网络请求。
WSGI is a specification that describes how a web server communicates with web applications, and how web applications can be chained together to process one request.
一个简单示例:
def application(environ, start_response):
status = '200 OK'
output = b'Hello World!'
response_headers = [('Content-type', 'text/plain'),
('Content-Length', str(len(output)))]
start_response(status, response_headers)
return [output]
Apache
Apache 通过 mod_wsgi
与 Python WSGI 例如 Django 实现通信:
- Apache 必须有权限访问这个脚本文件,以及脚本文件所在的路径
mod_wsgi
要求应用的入口为application
,亦即你不能修改这个函数名- 如果你一定要修改
application
这个函数名,那就需要在mod_wsgi
中进行配置
Apache 主要通过以下几种方式使用 WSGI 脚本:
- Apache 直接访问 WSGI 脚本
- WSGI 脚本作为后台进程运行
- 通过 mod_proxy 及其相关模块转发请求
为了方便查看 WSGI 错误,应该将 Apache 默认的日志级别从 warn 修改为 info:
LogLevel info
方法一,Apache 直接访问 WSGI 脚本
这里的核心是将一个 URL 与一个 WSGI 脚本关联起来,使用 WSGIScriptAlias
即可:
WSGIScriptAlias /myapp /usr/local/www/wsgi-scripts/myapp.wsgi
WSGIScriptAlias
指令的第一个参数为 /myapp
,表示访问 http://www.example.com/myapp
即调用对应 WSGI 脚本,注意第一个参数 /myapp
结尾处没有 /
,只有 WSGI 脚本作为 root URL 时可以写为 /
。
WSGIScriptAlias
指令只能放在 Apache 的主配置文件即 httpd.conf
,亦即不能置于 .htaccess
文件。
WSGIScriptAlias
指令可以放在 httpd.conf
全局,但更常见的是放在 VirtualHost
中,不能置于 Location
, Directory
, Files
配置中。
一个完整的配置示例:
<VirtualHost *:80>
ServerName www.example.com
ServerAlias example.com
DocumentRoot /usr/local/www/documents
<Directory /usr/local/www/documents>
Require all granted
</Directory>
WSGIScriptAlias /myapp /usr/local/www/wsgi-scripts/myapp.wsgi
<Directory /usr/local/www/wsgi-scripts>
Require all granted
</Directory>
</VirtualHost>
注意到,上例中我们的 Apache 根目录在 /usr/local/www/documents
,而 WSGI 脚本在 /usr/local/www/wsgi-scripts
,这样做的好处是即使 Apache 被错误地配置为了静态文件访问,我们的 Python 源代码也不会泄露。把所有的 Python 脚本放在一个独立的路径,是个更安全的做法。
扩展本示例 — 如果你的所有代码都用 WSGI 脚本实现,那么可以配置 root URL 指向 WSGI 脚本,即:
WSGIScriptAlias / /usr/local/www/wsgi-scripts/myapp.wsgi
这样有个副作用,就是位于 Apache 根目录的静态文件(如图片、视频等)就不能被访问了,因为所有请求都会转发到 WSGI 脚本处理。此时需要用 Alias
指定这些文件依然从 Apache 根目录访问。完整示例如下:
<VirtualHost *:80>
ServerName www.example.com
ServerAlias example.com
DocumentRoot /usr/local/www/documents
Alias /robots.txt /usr/local/www/documents/robots.txt
Alias /favicon.ico /usr/local/www/documents/favicon.ico
Alias /images/ /usr/local/www/documents/images/
<Directory /usr/local/www/documents>
Require all granted
</Directory>
WSGIScriptAlias /myapp /usr/local/www/wsgi-scripts/myapp.wsgi
<Directory /usr/local/www/wsgi-scripts>
Require all granted
</Directory>
</VirtualHost>
方法二,WSGI 脚本作为后台进程运行
在方法一中,WSGI 的运行模式成为嵌入模式(embedded mode),这个模式的一个问题在于如果 WSGI 脚本修改了,需要重启 Apache。更灵活的方式是将 WSGI 作为后台进程运行(daemon mode),在此种模式下当 WSGI 代码更新时,WSGI 进程将自动重启。这里的核心配置为:
WSGIDaemonProcess example.com processes=2 threads=15
WSGIProcessGroup example.com
一个完整的配置示例:
<VirtualHost *:80>
ServerName www.example.com
ServerAlias example.com
DocumentRoot /usr/local/www/documents
Alias /robots.txt /usr/local/www/documents/robots.txt
Alias /favicon.ico /usr/local/www/documents/favicon.ico
Alias /images/ /usr/local/www/documents/images/
<Directory /usr/local/www/documents>
Require all granted
</Directory>
WSGIDaemonProcess example.com processes=2 threads=15 display-name=%{GROUP}
WSGIProcessGroup example.com
WSGIScriptAlias /myapp /usr/local/www/wsgi-scripts/myapp.wsgi
<Directory /usr/local/www/wsgi-scripts>
Require all granted
</Directory>
</VirtualHost>