wsgirefPEP 333定义的wsgi规范的范例实现,里面的功能包括了:

  • wsgi的环境变量
  • 应答头部的处理
  • 实现简单的HTTP服务器
  • 简单的对程序端和服务器端校验函数

我们先看一个简单的代码实例,然后跟着例子去理解源码:

app.py

#encoding:utf-8
# __author__ = 'donghao'
# __time__ = 2019/3/29 14:17 def hello_world_app(environ, start_response):
from io import StringIO
stdout = StringIO()
start_response("200 OK", [('Content-Type','text/html; charset=utf-8')])
return ['<h1>hello world</h1>'.encode('utf-8')]

server.py

from wsgiref.simple_server import make_server
httpd = make_server('', 8000, hello_world_app)
print("Serving on port 8000...")
httpd.serve_forever()
#浏览器
"""
Content-Length: 20
Content-Type: text/html; charset=utf-8
Date: Fri, 29 Mar 2019 08:08:47 GMT
Server: WSGIServer/0.2 CPython/3.6.4
"""
#server终端
"""
Serving on port 8000...
127.0.0.1 - - [29/Mar/2019 16:19:12] "GET / HTTP/1.1" 200 20
"""

源码分析:

wsgiref

|-- handlers.py # 核心代码,负责 wsgi 程序的处理

|-- headers.py # 头部处理的代码

|-- init.py #

|-- simple_server.py # 简单的 wsgi HTTP 服务器实现

|-- util.py # 帮助函数

`-- validate.py # wsgi 格式检查和校验

主要的代码结构如下图所示:



simple_server.py

我们先看一下make_server是怎么启动一个wsgi服务器的:

def make_server(host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler):
server = server_class((host, port), handler_class)
server.set_app(app)
return server

这个函数做的事情就是:监听在本地的端口上,接受来自客户端的请求,通过WSGIServerWSGIRequestHandler处理后,把请求交给程序的的可调用对象app,然后返回app的结果给客户端。

这里有两个重要的类:WSGIServer和WSGIRequestHandler。下面分别看一下它们的代码和执行的功能。

WSGIServer

#WSGIServer
class WSGIServer(HTTPServer): """BaseHTTPServer that implements the Python WSGI protocol""" application = None def server_bind(self):
"""Override server_bind to store the server name."""
HTTPServer.server_bind(self)
self.setup_environ() def setup_environ(self):
# Set up base environment
env = self.base_environ = {}
env['SERVER_NAME'] = self.server_name
env['GATEWAY_INTERFACE'] = 'CGI/1.1'
env['SERVER_PORT'] = str(self.server_port)
env['REMOTE_HOST']=''
env['CONTENT_LENGTH']=''
env['SCRIPT_NAME'] = '' def get_app(self):
return self.application def set_app(self,application):
self.application = application

WSGIServer在原来的HTTPServer上面封装了一层,在原来的HTTPServer的基础上又额外做了下面的事情:

  • 覆写原来的server_bind函数,添加初始化environ变量的动作
  • 添加了处理满足wsgi的app函数set_appget_app

WSGIRequestHandler

# WSGIRequestHandler
class WSGIRequestHandler(BaseHTTPRequestHandler): server_version = "WSGIServer/" + __version__ def get_environ(self):
env = self.server.base_environ.copy()
env['SERVER_PROTOCOL'] = self.request_version
env['REQUEST_METHOD'] = self.command
if '?' in self.path:
path,query = self.path.split('?',1)
else:
path,query = self.path,'' env['PATH_INFO'] = urllib.unquote(path)
env['QUERY_STRING'] = query host = self.address_string()
if host != self.client_address[0]:
env['REMOTE_HOST'] = host
env['REMOTE_ADDR'] = self.client_address[0] if self.headers.typeheader is None:
env['CONTENT_TYPE'] = self.headers.type
else:
env['CONTENT_TYPE'] = self.headers.typeheader length = self.headers.getheader('content-length')
if length:
env['CONTENT_LENGTH'] = length for h in self.headers.headers:
k,v = h.split(':',1)
k=k.replace('-','_').upper(); v=v.strip()
if k in env:
continue # skip content length, type,etc.
if 'HTTP_'+k in env:
env['HTTP_'+k] += ','+v # comma-separate multiple headers
else:
env['HTTP_'+k] = v
return env def get_stderr(self):
return sys.stderr def handle(self):
"""Handle a single HTTP request""" self.raw_requestline = self.rfile.readline()
if not self.parse_request(): # An error code has been sent, just exit
return handler = ServerHandler(
self.rfile, self.wfile, self.get_stderr(), self.get_environ()
)
handler.request_handler = self # backpointer for logging
handler.run(self.server.get_app())

这个类从名字就能知道它的功能 - 处理客户端的HTTP请求,它也是在原来处理http请求的BaseHTTPRequestHandler类上添加了wsgi规范相关的内容。

get_environ:解析环境变量

handle:处理请求,把封装的环境变量交给ServerHandler,然后由ServerHandler调用wsgi appServerHandler类会在下面介绍。

handler.py

这个文件主要是wsgi server的处理过程,定义start_response,调用wsgi app,处理content-length等等。


一条HTTP请求的旅程

服务器端启动服务,等到客户端输入curl -i http://localhost:8000/命令,摁下回车键,看到终端上的输出,整个过程中,wsgi的服务器端发生了什么呢?

  1. 服务器程序创建socket,并监听在特定的端口,等待客户端的连接
  2. 客户端发送http请求
  3. socket服务器读取请求的数据,交给http服务器
  4. http server根据http的规范解析请求,然后把请求交给WSGIServer
  5. WSGIServer把客户端的信息存放在环境变量里,然后交给绑定的handler handler理请求
  6. HTTPHandler解析请求,把方法,路径等放在environ,然后WSGIRequestHandler把服务器端的信息也放到environ里
  7. WSGIRequestHandler调用绑定的wsgi ServerHandler,把上面包含了服务器信息,客户端信息,本次请求信息得environ传递过去
  8. wsgi ServerHandler调用注册的wsgi app,把环境和start_response传递过去
  9. wsgi app将响应头,状态,身体回传给wsgi处理程序
  10. 然后处理器逐层传递,最后把这些信息通过socket发送到客户端
  11. 客户端的程序接到应答,解析应答,并把结果打印出来

    ![在这里插入图片描述](https://img-blog.csdnimg.cn/2019032916561883.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyMjM5NTIw,size_16,color_FFFFFF,t_70 =2000x800)

    自己画的图,虽有点丑,回顾还是很有用。

wsgiref源码解析的更多相关文章

  1. wsgiref 源码解析

    Web Server Gateway Interface(wsgi),即Web服务器网关接口,是Web服务器软件和用Python编写的Web应用程序之间的标准接口. 想了解更多关于WSGI请前往: h ...

  2. 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新

    本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...

  3. 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新

    [原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...

  4. 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新

    上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...

  5. 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...

  6. jQuery2.x源码解析(缓存篇)

    jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 缓存是jQuery中的又一核心设计,jQuery ...

  7. Spring IoC源码解析——Bean的创建和初始化

    Spring介绍 Spring(http://spring.io/)是一个轻量级的Java 开发框架,同时也是轻量级的IoC和AOP的容器框架,主要是针对JavaBean的生命周期进行管理的轻量级容器 ...

  8. jQuery2.x源码解析(构建篇)

    jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 笔者阅读了园友艾伦 Aaron的系列博客< ...

  9. jQuery2.x源码解析(设计篇)

    jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 这一篇笔者主要以设计的角度探索jQuery的源代 ...

随机推荐

  1. eclipse Maven Dependencies 黑色背景说明

    记录工作点点滴滴,大到系统设计,源码分析,小到IDE设置. 这里要说的是eclipse中Maven Dependencies 为什么有些jar用黑色背景,如下图所示: 网上很多人说jar包在本地仓库不 ...

  2. openstack镜像制作centos7

    1,找一台宿主机安装kvm并检查是否支持虚拟化,这里我用的是vmware来做宿主机 egrep '(vmx|svm)' /proc/cpuinfo 然后安装kvm: yum install epel- ...

  3. VSCode 绿色版(zip压缩包) 添加右键菜单 使用VSCode 打开文件或文件夹

    微软官方下载VSCode 可以下载exe安装外还可以下载zip 压缩包 下载地址: https://code.visualstudio.com/Download 但是zip压缩包却没有了 右键使用VS ...

  4. list常用方法

    1.切片: ①.顾头不顾尾,从头开始取,但不包括最后一个. ②.从左向右数为正,从零开始,从右开始为负,从-1开始 如: names=['1','2','3'] ames[-1]与names[2]效果 ...

  5. A Senior Interview

    1.How many time did they spent to plan the final project? 答:两天左右,两次开会. 4.How many time did they spen ...

  6. 20175316盛茂淞 2018-2019-2 《Java程序设计》第6周学习总结

    20175316盛茂淞 2018-2019-2 <Java程序设计>第6周学习总结 教材学习内容总结 第7章 内部类与异常类 1.使用 try.catch Java中所有信息都会被打包为对 ...

  7. excel支持正则表达式提取字符函数(支持RegExp捕获分组)

    一.要让excel脚本支持Microsoft VBScript Regular Expressions 5.5 ,按快捷键alt+F11,出现下图界面,操作如图示: 二.添加VBA代码: 代码添加完毕 ...

  8. 手写简单PE

    环境工具:Windows 10 010Editor 目标程序功能: 调用MessageBoxA弹出消息框. 1.构造DOS头 typedef struct _IMAGE_DOS_HEADER { // ...

  9. LOJ-10104(割点+dfs)

    题目链接:传送门 思路: 求割点的同时求割点删除后所剩的不连通的点的对数,在遍历完成后回溯统计点的个数,具体操作见代码: 注意:结果是long long 类型. #include<iostrea ...

  10. VS2017 Debug断点后显示UTF8字符串

    断点后跟踪字幕文件文本,因为国内字幕一般是UTF8的,VS默认显示不出来,在变量上双击,加入 ,s8就可以了 默认 修改后 其他 ,数字  将变量拆分为数组显示, 数字是要显示多少位, 此法对cons ...