WSGI到底是什么?
在用Python Web开发时经常会遇到WSGI,所以WSGI到底是什么呢?本文我们一起来揭开WSGI神秘的面纱!
先来看一下WSGI的介绍:
全称Python Web Server Gateway Interface,指定了web服务器和Python web应用或web框架之间的标准接口,以提高web应用在一系列web服务器间的移植性。 具体可查看 官方文档
从以上介绍我们可以看出:
- WSGI是一套接口标准协议/规范;
- 通信(作用)区间是Web服务器和Python Web应用程序之间;
- 目的是制定标准,以保证不同Web服务器可以和不同的Python程序之间相互通信
你可能会问,为什么需要WSGI?
首先,我们明确一下web应用处理请求的具体流程:
- 用户操作操作浏览器发送请求;
- 请求转发至对应的web服务器
- web服务器将请求转交给web应用程序,web应用程序处理请求
- web应用将请求结果返回给web服务器,由web服务器返回用户响应结果
- 浏览器收到响应,向用户展示
可以看到,请求时Web服务器需要和web应用程序进行通信,但是web服务器有很多种啊,Python web应用开发框架也对应多种啊,所以WSGI应运而生,定义了一套通信标准。试想一下,如果不统一标准的话,就会存在Web框架和Web服务器数据无法匹配的情况,那么开发就会受到限制,这显然不合理的。
既然定义了标准,那么WSGI的标准或规范是?
web服务器在将请求转交给web应用程序之前,需要先将http报文转换为WSGI规定的格式。
WSGI规定,Web程序必须有一个可调用对象,且该可调用对象接收两个参数,返回一个可迭代对象:
- environ:字典,包含请求的所有信息
- start_response:在可调用对象中调用的函数,用来发起响应,参数包括状态码,headers等
通过以上学习,一起实现一个简单WSGI服务吧
首先,我们编写一个符合WSGI标准的一个http处理函数:
def hello(environ, start_response):
status = "200 OK"
response_headers = [('Content-Type', 'text/html')]
start_response(status, response_headers)
path = environ['PATH_INFO'][1:] or 'hello'
return [b'<h1> %s </h1>' % path.encode()]
该方法负责获取environ字典中的path_info,也就是获取请求路径,然后在前端展示。
接下来,我们需要一个服务器启动WSGI服务器用来处理验证,使用Python内置的WSGI服务器模块wsgiref,编写server.py:
# coding:utf-8
"""
desc: WSGI服务器实现
"""
from wsgiref.simple_server import make_server
from learn_wsgi.client import hello
def main():
server = make_server('localhost', 8001, hello)
print('Serving HTTP on port 8001...')
server.serve_forever()
if __name__ == '__main__':
main()
执行python server.py,浏览器打开"http://localhost:8001/a",即可验证。
通过实现一个简单的WSGI服务,我们可以看到:通过environ可以获取http请求的所有信息,http响应的数据都可以通过start_response加上函数的返回值作为body。
当然,以上只是一个简单的案例,那么在python的Web框架内部是如何遵循WSGI规范的呢?以Flask举例,
Flask与WSGI
Flask中的程序实例app就是一个可调用对象,我们创建app实例时所调用的Flask类实现了__call__方法,__call__方法调用了wsgi_app()方法,该方法完成了请求和响应的处理,WSGI服务器通过调用该方法传入请求数据,获取返回数据:
def wsgi_app(self, environ, start_response):
ctx = self.request_context(environ)
error = None
try:
try:
ctx.push()
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except: # noqa: B001
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
ctx.auto_pop(error)
def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)
Flask的werkzeug库是一个非常优秀的WSGI工具库,具体的实现我们之后再详细学习。
以上。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 未来的神器fiddler Everywhere
- Sentinel整合Apollo进行规则持久化
- DevTools(Chrome 85)的新功能
- 在Node.js中处理Zip文件
- 构建一个带身份验证的 Deno 应用
- Sentinel整合Apollo进行规则持久化(二)
- Sentinel整合Apollo进行规则持久化(三)
- BeesCMS的SQL注入漏洞
- 操作系统的演变及在云计算的应用
- 没root账号,如何安装perl包
- 从 BIO、NIO 聊到 Netty,还要手写一个 RPC 框架!毕设/项目经验稳了!
- 从100万条数据中找到极大值所在行
- 常考题 | IoU 计算
- 操作系统和并发的爱恨纠葛
- Vue Router详细教程