Reinventing the wheel is great if your goal is to learn more about wheels.” – James Tauber
python web 框架众多,大而全的 django,小巧的 flask,支持异步的 tornado 等,可能是因为用 python 实现个 web 框架太简单了吧,python 的框架层出不穷。 下边一步步介绍下一个 web 框架的基础组成,以及如何写个简单的 web 框架(使用 python3),从而了解下 web 框架的工作原理。
WSGI
首先要了解 WSGI 规范的概念,WSGI(Web Server Gateway Interface)规范描述了web server(Gunicorn,uWSGI等)如何与web application(flask, django等)交互、web application如何处理请求,定义在 pep 3333。正是有了 WSGI 规范,我们才能在任意 web server 上跑各种 web 应用。WSGI API 定义看起来很简单:
def application(environ, start_response)application 就是 WSGI app,一个可调用对象
参数:environ: 一个包含 WSGI 环境信息的字典,由 WSGI 服务器提供,常见的 key 有 PATH_INFO,QUERY_STRING 等
start_response: 生成 WSGI 响应的回调函数,接收两个参数,status 和 headers
函数返回响应体的迭代器
下面举个简单的例子,比如一个返回 hello world 的应用:
def application(environ, start_response):
status = '200 OK'
headers = [('Content-Type', 'text/html; charset=utf8')]
start_response(status, headers)
return [b"
Hello, World!
"]接下来我们使用 python 内置的 wsgi server 来跑这个应用:
# 导入python内置的WSGI server
from wsgiref.simple_server import make_server
def application(environ, start_response):
print(environ) # 我建议你打出来这个字典看看有哪些参数
status = '200 OK'
headers = [('Content-Type', 'text/html; charset=utf8')]
start_response(status, headers)
return [b"
Hello, World!
"] # WSGI applications return iterables that yield bytesif __name__ == '__main__':
httpd = make_server('127.0.0.1', 8888, application)
httpd.serve_forever()
运行这个文件,使用浏览器或者 curl 等工具访问 http://localhost:8888 就能看到结果了。如果你打出来了 environ,能看到很多由 WSGI 服务器提供的环境信息,常见的有以下几个:
KeyContentsPATH_INFO请求路径,比如 /foo/bar/QUERY_STRINGGET 请求参数,比如 foo=bar&bar=spam,我们可以从这个变量中获取用户的请求参数HTTP_{HEADER}http 头信息,比如 HTTP_HOST 等wsgi.input包含请求内容的类文件对象(file-like object),比如 post 请求数据
接下来看看 start_response 这个可调用对象:
status = '200 OK'
headers = [('Content-Type', 'text/html; charset=utf8')]
start_response(status, headers)
start_response 接收两个参数 :
start_response(status, head