摘要:原地址介绍要很好地理解下面的代码,最好有一定的编程基础,了解的基本概念和流程。这个文件主要是的处理过程,定义调用处理等等。
原地址:http://cizixs.com/2014/11/09/...1. 介绍
要很好地理解下面的代码,最好有一定的 socket 编程基础,了解 socket 的基本概念和流程。
wsgiref 是 PEP 333 定义的 wsgi 规范的范例实现,里面的功能包括了:
操作 wsgi 的环境变量
应答头部的处理
实现简单的 HTTP server
简单的对程序端和服务器端校验函数
我们先看一个简单的代码实例,然后跟着例子去理解源码:
1.1 app.py# pep333 定义的程序端可调用对象 def hello_world_app(environ, start_response): status = "200 OK" # HTTP Status headers = [("Content-type", "text/plain")] # HTTP Headers start_response(status, headers) # The returned object is going to be printed return ["Hello World"]1.2 server.py
from app import hello_world_app from wsgiref.simple_server import make_server httpd = make_server("", 8000, hello_world_app) print "Serving on port 8000..." # Serve until process is killed httpd.serve_forever()
然后执行 python server.py 启动 sever,用 curl 发送一个请求 curl -i http://localhost:8000/,会有以下输出:
HTTP/1.0 200 OK Date: Sat, 08 Nov 2014 09:08:05 GMT Server: WSGIServer/0.1 Python/2.7.3 Content-type: text/plain Content-Length: 12 Hello World
server 的终端会有一条记录:
Serving on port 8000... localhost - - [08/Nov/2014 09:08:05] "GET / HTTP/1.1" 200 122. 源码分析
你可以使用 python -c "import wsgiref; help(wsgiref)" 查看 wsgiref 库的路径和简介等信息,wsgiref 文件夹的结构如下:
wsgiref |-- handlers.py # 核心代码,负责 wsgi 程序的处理 |-- headers.py # 头部处理的代码 |-- __init__.py # |-- simple_server.py # 简单的 wsgi HTTP 服务器实现 |-- util.py # 帮助函数 `-- validate.py # wsgi 格式检查和校验
主要的代码结构如下图所示:
我们先看一下 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
这个函数做的事情就是:监听在本地的端口上,接受来自客户端的请求,通过 WSGIServer 和 WSGIRequestHandler 处理后,把请求交给程序的的可调用对象 app,然后返回 app 的结果给客户端。
这里有两个重要的类:WSGIServer 和 WSGIRequestHandler。下面分别看一下它们的代码和执行的功能。
2.2 WSGIServerclass 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_app 和 get_app
2.3 WSGIRequestHandlerclass 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: 解析 environ 变量
handle: 处理请求,把封装的环境变量交给 ServerHandler,然后由 ServerHandler 调用 wsgi app,ServerHandler 类会在下面介绍。
2.4 handler.py这个文件主要是 wsgi server 的处理过程,定义 start_response、调用 wsgi app 、处理 content-length 等等。
2.5 UML类图 3. 一条 HTTP 请求的过程服务器端启动服务,等到客户端输入 curl -i http://localhost:8000/ 命令,摁下回车键,看到终端上的输出,整个过程中,wsgi 的服务器端发生了什么呢?
服务器程序创建 socket,并监听在特定的端口,等待客户端的连接
客户端发送 http 请求
socket server 读取请求的数据,交给 http server
http server 根据 http 的规范解析请求,然后把请求交给 WSGIServer
WSGIServer 把客户端的信息存放在 environ 变量里,然后交给绑定的 handler 处理请求
HTTPHandler 解析请求,把 method、path 等放在 environ,然后 WSGIRequestHandler 把服务器端的信息也放到 environ 里
WSGIRequestHandler 调用绑定的 wsgi ServerHandler,把上面包含了服务器信息,客户端信息,本次请求信息得 environ 传递过去
wsgi ServerHandler 调用注册的 wsgi app,把 environ 和 start_response 传递过去
wsgi app 将reponse header、status、body 回传给 wsgi handler
然后 handler 逐层传递,最后把这些信息通过 socket 发送到客户端
客户端的程序接到应答,解析应答,并把结果打印出来。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/41435.html
摘要:对背后运行机制感兴趣,参考网上资料,结合源码分析函数运行时的机制,主要整理出函数调用栈。以分析首先官方文档经典示例现在来分析启动时发生了什么代码只列出用到的函数,去掉注释等函数导入运行函数主要运行调用返回类,然后调用返回类的。 对flask背后运行机制感兴趣,参考网上资料,结合源码分析run函数运行时的机制,主要整理出函数调用栈。以flask0.1分析 首先Flask官方文档经典示例 ...
摘要:一般来说,这一例行程序用于处理请求的每一部分,例如把路径作为一系列字典键值进行处理。,必须是按照中所规定地键值元组列表。行为时回车换行。这个包装器也可能用模块指明那些有问题的,但不完全违反的行为。 wsgirf-WSGI功能及参考实现 源码:Lib/wsgiref Web服务器网关接口(Web Server Gateway Interface, WSGI),是用Python写的一个服务...
摘要:所以,我按照自己的逻辑总结了一下项目的运行方式和对的基本处理流程。二请求处理流程和其他框架一样,的处理流程基本类似接受,返回内容。在中,中间件组件用字符串表示指向中间件类名的完整路径。 之前在网上看过一些介绍Django处理请求的流程和Django源码结构的文章,觉得了解一下这些内容对开发Django项目还是很有帮助的。所以,我按照自己的逻辑总结了一下Django项目的运行方式和对Re...
摘要:回顾通过前几篇文章的内容我们已经搭建了基于框架的一个简单的应用的代码如下此外我们还为其申请了公网和域名并且部署了的证书现在当我们在浏览器地址栏输入即可访问我们的网站不过我们的网站目前还存在几个问题无法访问每次都需要用户手动输入前缀以制定形式 回顾 通过前几篇文章的内容, 我们已经搭建了基于 Flask 框架的一个简单的 Web 应用, server.py 的代码如下 from f...
阅读 1861·2021-09-22 15:45
阅读 1642·2019-08-30 15:55
阅读 1831·2019-08-29 11:16
阅读 3306·2019-08-26 11:44
阅读 707·2019-08-23 17:58
阅读 2699·2019-08-23 12:25
阅读 1626·2019-08-22 17:15
阅读 3604·2019-08-22 16:09