WSGI

1. 什么是WSGI

Web服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI)是为Python语言定义的Web服务器Web应用程序框架之间的一种简单而通用的接口。自从WSGI被开发出来以后,许多其它语言中也出现了类似接口。

 

2. 发展历史

1989年

 

 

 

特点:

server只能返回静态文件,例如html,css,image等静态文件

 

过程:服务器收到request请求,知道要获取index.html,服务器从硬盘中读取index.html的内容, 将读取的内容放在body中返回。

 

1991年

需求:想让服务器返回html form表单

 

 

特点:

 

1997年

出现了公共的网管接口:CGI

目的是为了设置一组规范,命名一些环境变量,以及声明它们的用途。

公共网关接口(Common Gateway Interface,CGI)是Web 服务器运行时外部程序的规范,按CGI 编写的程序可以扩展服务器功能。
CGI 应用程序能与浏览器进行交互,还可通过数据API与数据库服务器等外部数据源进行通信,从数据库服务器中获取数据。格式化为HTML文档后,发送给浏览器,也可以将从浏览器获得的数据放到数据库中。几乎所有服务器都支持CGI,可用任何语言编写CGI,
包括流行的C、C ++、Java、VB 和Delphi 等。CGI分为标准CGI和间接CGI两种。标准CGI使用命令行参数或环境变量表示服务器的详细请求,服务器与浏览器通信采用标准输入输出方式。间接CGI又称缓冲CGI,在CGI程序和CGI接口之间插入一个缓冲程序,
缓冲程序与CGI接口间用标准输入输出进行通信

 

 规定了下图的内容

 

 

2003年

 

 

python为了进一步的执行cgi的标准,因此规定了标准化脚本,任何从web服务器调用脚本,都必须拥有类似于nerdy的函数。函数接受两个变量,env是一个dict字典,用来存储cgi规定的变量。foo是一个特殊参数(函数),只需要已特定的方式调用第二个参数即可。

foo函数的两个参数
1. http_status --- response的status
2. http_headers_list --- response的headers

 

nerdy函数返回值,就是response的body部分

 

3. 自己实现WSGI的转发

实现WSGI转发,需要实现wsgi服务器(类似于gunicorn)和application(类似于flask/django)

3.1 实现wsgi服务器

# encoding:utf-8
# @Time : 2021/6/27 6:20 下午
# @Author : yan
# @Content: 模仿wsgi服务器, 类似于gunicorn

from wsgiref.simple_server import make_server
from web服务器的实现原理.WSGI协议转发.application import application

# 类似于gunicorn配置文件的bind, 启动 gunicron -c gun.py application:applicaton
httpd = make_server('127.0.0.1', 9000, application)
print("Serving HTTP on port 9000...")
# 开始监听HTTP请求:
httpd.serve_forever()

 

3.2实现web应用程序

# encoding:utf-8
# @Time : 2021/6/27 6:20 下午
# @Author : yan
# @Content: 模仿flask应用

def application(environ, start_response):
    """
    这个函数flask或者django已经封装好了,里面的request对象,会将environ的参数进行绑定。
    """
    # environ {'PATH': '/Users/yanyanzhang/opt/anaconda3/bin:/Users/yanyanzhang/opt/anaconda3/condabin:/usr/local/sbin:/usr/local/bin:/Library/Frameworks/Python.framework/Versions/3.7/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/VMware Fusion.app/Contents/Public:/usr/local/go/bin:/usr/local/mysql/bin:/usr/local/go/bin:/Users/yanyanzhang/goProject', 'CONDA_DEFAULT_ENV': 'base', 'CONDA_EXE': '/Users/yanyanzhang/opt/anaconda3/bin/conda', 'JAVA_HOME': '/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home', 'CONDA_PYTHON_EXE': '/Users/yanyanzhang/opt/anaconda3/bin/python', 'LANG': 'en_US.UTF-8', 'CONDA_PREFIX': '/Users/yanyanzhang/opt/anaconda3', '_CE_M': '', 'LOGNAME': 'yanyanzhang', 'XPC_SERVICE_NAME': 'com.jetbrains.pycharm.3452', 'PWD': '/Users/yanyanzhang/leifeng/leifeng-python-knowledge/web服务器的实现原理/WSGI协议转发', 'PYCHARM_HOSTED': '1', 'CONDA_SHLVL': '1', 'PYCHARM_DISPLAY_PORT': '63342', 'PYTHONPATH': '/Users/yanyanzhang/leifeng/leifeng-python-knowledge:/Applications/PyCharm.app/Contents/plugins/python/helpers/pycharm_matplotlib_backend:/Applications/PyCharm.app/Contents/plugins/python/helpers/pycharm_display', 'SHELL': '/bin/bash', 'PYTHONIOENCODING': 'UTF-8', 'HOMEBREW_BOTTLE_DOMAIN': 'https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles', 'GOPATH': '/Users/yanyanzhang/goProject', 'USER': 'yanyanzhang', 'GOROOT': '/usr/local/go', 'TMPDIR': '/var/folders/93/gyvmf3qj2w3ft0yj47rtpnmr0000gn/T/', 'SSH_AUTH_SOCK': '/private/tmp/com.apple.launchd.tNGhZcQUd3/Listeners', 'GOBIN': '/usr/local/go/bin', '_CE_CONDA': '', 'XPC_FLAGS': '0x0', 'PYTHONUNBUFFERED': '1', 'LC_ALL': 'en_US.UTF-8', '__CF_USER_TEXT_ENCODING': '0x1F5:0x19:0x34', 'Apple_PubSub_Socket_Render': '/private/tmp/com.apple.launchd.hD6UGiLN7J/Render', 'CONDA_PROMPT_MODIFIER': '(base) ', 'HOME': '/Users/yanyanzhang', '__PYVENV_LAUNCHER__': '/Library/Frameworks/Python.framework/Versions/3.7/bin/python3.7', 'SERVER_NAME': '1.0.0.127.in-addr.arpa', 'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_PORT': '9000', 'REMOTE_HOST': '', 'CONTENT_LENGTH': '', 'SCRIPT_NAME': '', 'SERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SOFTWARE': 'WSGIServer/0.2', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/', 'QUERY_STRING': '', 'REMOTE_ADDR': '127.0.0.1', 'CONTENT_TYPE': 'text/plain', 'HTTP_HOST': '127.0.0.1:9000', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_CACHE_CONTROL': 'max-age=0', 'HTTP_SEC_CH_UA': '" Not A;Brand";v="99", "Chromium";v="90", "Google Chrome";v="90"', 'HTTP_SEC_CH_UA_MOBILE': '?0', 'HTTP_UPGRADE_INSECURE_REQUESTS': '1', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36', 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 'HTTP_SEC_FETCH_SITE': 'none', 'HTTP_SEC_FETCH_MODE': 'navigate', 'HTTP_SEC_FETCH_USER': '?1', 'HTTP_SEC_FETCH_DEST': 'document', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br', 'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9', 'HTTP_COOKIE': 'csrftoken=yuqdKIvcb4n1XDwwM8APng4df84hlLQ1sZead7YBshaS1fITeUI6awsUTEWD1q9L', 'wsgi.input': <_io.BufferedReader name=5>, 'wsgi.errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>, 'wsgi.version': (1, 0), 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.multithread': True, 'wsgi.multiprocess': False, 'wsgi.file_wrapper': <class 'wsgiref.util.FileWrapper'>}
    print("environ", environ)
    # start response <bound method BaseHandler.start_response of <wsgiref.simple_server.ServerHandler object at 0x10bce5f60>>
    print("start response", start_response)
    response_body = '<h1>Hello, web!</h1>'
    start_response('200 OK', [('Content-Type', 'text/html')])
    return [response_body.encode("utf-8")]

 

浏览器请求结果

 

4. werkzeug文档

Werkzeug 并不是 一个框架,它是一个 WSGI 工具集的库,你可以通过它来创建你自己的框架或 Web 应用。

pip3 install Werkzeug

pip3 install Jinja2

3.2 中的 application


def application(environ, start_response):
print("start response", start_response) response_body = '<h1>Hello, web!</h1>'
   # start_response是WSGI传递进来的一个方法,可以和环境进行通信,环境包含了进来的所有信息,start_response表明收到了一个响应。
  start_response('200 OK', [('Content-Type', 'text/html')]) return [response_body.encode("utf-8")]

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

# TODO

posted @ 2021-06-19 22:42  张京墨  阅读(324)  评论(0编辑  收藏  举报