最近在读Flask0.1的源码,Flask框架饱受好评的原因就是因为简洁,明快而且够Pythonic,于是自己也关注了一下,尝试从底层读懂flask的代码.(可能有没有理解对的地方)

虽然Flask0.1的代码量只有不到700行,但是读懂并不容易,再此之前还需要wsgi的一些基础知识,google好多资料,发现很难让初学者了解整个架构的情况,廖学峰老师的这篇文章给了我很大的帮助,画出一张简图,来看看整个网站的接口是如何链接的,然后再从内部逐一理解python的web框架原理.

可以看到这里有三个层次:

  1. web框架层
  2. wsgi层
  3. web服务器

1 web框架层

在这里作为网站开发者只需要了解框架给我们的方法,我们可以使用框架快速开发我们的网站,它可以帮我们管理数据库,管理cookies,管理我们的路由.

通过Flask框架我们可以很快的写一个网页:

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

    if __name__ == "__main__":
        app.run()

2 wsgi层

wsgi其实是一种规范,它定义了web app和web服务器的接口,其实wsgi层和web框架层可以看为一层(即在web框架实现wsgi面向web服务器的接口).wsgi层是框架的开发者关心的层面.框架需要为服务器提供标准的接口,在pep3333里有详细的文档:

# pep3333中的例子
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']

这里不用关心environ, start_response, 它由web服务器提供.

3 web服务器层

作为服务器端也有必要提供wsgi的服务器端接口.

import os, sys

def run_with_cgi(application):

    environ = dict(os.environ.items())
    environ['wsgi.input']        = sys.stdin
    environ['wsgi.errors']       = sys.stderr
    environ['wsgi.version']      = (1, 0)
    environ['wsgi.multithread']  = False
    environ['wsgi.multiprocess'] = True
    environ['wsgi.run_once']     = True

    if environ.get('HTTPS', 'off') in ('on', '1'):
        environ['wsgi.url_scheme'] = 'https'
    else:
        environ['wsgi.url_scheme'] = 'http'

    headers_set = []
    headers_sent = []

    def write(data):
        if not headers_set:
             raise AssertionError("write() before start_response()")

        elif not headers_sent:
             # Before the first output, send the stored headers
             status, response_headers = headers_sent[:] = headers_set
             sys.stdout.write('Status: %s\r\n' % status)
             for header in response_headers:
                 sys.stdout.write('%s: %s\r\n' % header)
             sys.stdout.write('\r\n')

        sys.stdout.write(data)
        sys.stdout.flush()

    def start_response(status, response_headers, exc_info=None):
        if exc_info:
            try:
                if headers_sent:
                    # Re-raise original exception if headers sent
                    raise exc_info[0], exc_info[1], exc_info[2]
            finally:
                exc_info = None     # avoid dangling circular ref
        elif headers_set:
            raise AssertionError("Headers already set!")

        headers_set[:] = [status, response_headers]
        return write

    result = application(environ, start_response)
    try:
        for data in result:
            if data:    # don't send headers until body appears
                write(data)
        if not headers_sent:
            write('')   # send headers now if body was empty
    finally:
        if hasattr(result, 'close'):
            result.close()

最后通过wsgi,web服务器和框架之间可以连接起来了.

其实最简单的理解还是wsgi作为一个服务器端和web框架(Python)之间的接口.个中细节只有到源码里才能体会.