直接使用uWSGI来运行Django

简介

Python应用提供Web服务,往往需要一种连接网关与应用的中间件。

通常使用WSGI规范来连接,而uWSGI则是一个实现这个规范的软件。

WSGI简介

网络服务器网关接口(Web Server Gateway Interface,缩写WSGI), 是为Python定义的一套简单而通用的规范, 用于连接网络服务器与网络应用或框架。

The Web Server Gateway Interface (WSGI) is a specification for simple and universal interface between web servers and web applications or frameworks for the Python programming language.

版本 文档 日期
1.0 PEP-333 2003-12-07
1.0.1 PEP-3333 2010-09-26

uWSGI简介

uWSGI是一个Web应用服务器,与Nginx、Apache类似,只是没那么全能。 而且,在需要实现WSGI规范时, Nginx是通过ngx_http_uwsgi_module的uwsgi_pass与uwsgi_params来支持, 而Apache是通过mod_uwsgimod_proxy_uwsgi来支持。

uWSGI项目,开源托管于GitHub。 它主要由C语言构成,也包含C++、Python、Ruby、Java等语言的包装。

uWSGI目前(2017年7月),已经发展到了2.0.15版本。 除了主要支持Python以外,它还对Lua、Perl、Ruby、Erlang、PHP、Go、JVM等,提供了不同程度的支持。

uWSGIunbit.com提供商业技术支持。 该公司还另外提供一个更强大的Unbit hosting platform,是uWSGI的强化版。

使用

在一个具备Python的环境下,用pip install uWSGI就可安装。

在Docker中会麻烦一些,详见孤之前写的《在Docker中安装uWSGI》。

uWSGI的简单使用

把以下内容,写入hello_wsgi.py文件。 这就是一个简单的Hello World网络应用了。

def application(env, start_response):
    start_response('200 OK', [('Content-Type','text/html')])
    return [b"Hello World"]

uwsgi命令,在8000端口运行。 然后可以在浏览器中,看到返回结果。

$ uwsgi --http :8000 --wsgi-file hello_wsgi.py

Django生成的wsgi.py

在目前最新的1.11版本中,通过Django的startproject命令,可以生成一个wsgi.py

$ django-admin startproject mytest
$ tree mytest/
mytest/
├── manage.py
└── mytest
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

进入mytest目录,运行./manage.py runserver,即可在8000端口看到新生成的项目首页。

runserver是调试用的。

正式使用时,可以指定wsgi.py文件给uWSGI

$ uwsgi --http :8000 --wsgi-file mytest/wsgi.py

wsgi.py的内容

Django自动生成的wsgi.py文件短小精干:

import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mytest.settings")

application = get_wsgi_application()

而打开django.core.wsgi模块,可以看到get_wsgi_application函数,只是一次简单的转交。

import django
from django.core.handlers.wsgi import WSGIHandler


def get_wsgi_application():
    """
    The public interface to Django's WSGI support. Should return a WSGI
    callable.

    Allows us to avoid making django.core.handlers.WSGIHandler public API, in
    case the internal WSGI implementation changes or moves in the future.
    """
    django.setup(set_prefix=False)
    return WSGIHandler()

django.core.handlers.wsgi模块,WSGIHandler的代码如下:

class WSGIHandler(base.BaseHandler):
    request_class = WSGIRequest

    def __init__(self, *args, **kwargs):
        super(WSGIHandler, self).__init__(*args, **kwargs)
        self.load_middleware()

    def __call__(self, environ, start_response):
        set_script_prefix(get_script_name(environ))
        signals.request_started.send(sender=self.__class__, environ=environ)
        request = self.request_class(environ)
        response = self.get_response(request)

        response._handler_class = self.__class__

        status = '%d %s' % (response.status_code, response.reason_phrase)
        response_headers = [(str(k), str(v)) for k, v in response.items()]
        for c in response.cookies.values():
            response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
        start_response(force_str(status), response_headers)
        if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
            response = environ['wsgi.file_wrapper'](response.file_to_stream)
        return response

可见,WSGIHandler与之前的hello_wsgi.py,形式上也差不多。 这就是实现WSGI的关键内容。

在没有自动生成wsgi.py的Django老版本,可以通过上述内容,自己写一个。

uWSGI配置

uwsgi命令的参数太多了。 在当前版本下,光帮助文档就有近千行。

$ uwsgi -h | wc
    997    8772   92257

使用wsgi.py的配置

在复杂情况下,利用配置文件,是更好的选择。 例如,前面的uwsgi --http :8000 --wsgi-file mytest/wsgi.py, 可以写成如下形式的mytest.ini文件。

[uwsgi]
http = :8000
wsgi-file = mytest/wsgi.py

然后,通过uwsgi mytest.ini,即可执行。

不使用wsgi.py的配置

wsgi.py不是必须的。

[uwsgi]
http = :8000
env = DJANGO_SETTINGS_MODULE=mytest.settings
module = django.core.wsgi:get_wsgi_application()

这一配置,相当于重写了wsgi.py文件的内容。

Django 1.4以前的配置

对Django 1.4以前的版本,不会自动生成wsgi.py文件,也没有get_wsgi_application函数。

可以使用以下配置去替代。

[uwsgi]
http = :8000
env = DJANGO_SETTINGS_MODULE=mytest.settings
module = django.core.handlers.wsgi:WSGIHandler()

注意:这一写法在1.4及以上版本无效,因为那以后的Django需要初始化。

错误提示:

django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.

其它配置

上面展示的是必须的最简配置。 除此之外,以下配置也较为常见。

[uwsgi]
chdir = /PATH/TO/YOUR/PROJECT
master = true
processes = 4
threads = 2
stats = 127.0.0.1:9191
static-map = /static=/PATH/TO/DJANGO/STATIC

以上配置的具体含义,以及其它更多的配置,可以查看uwsgi -h, 或者官方文档《uWSGI Options — uWSGI

参考


相关笔记