浅析WSGI协议
Posted 林树楷
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅析WSGI协议相关的知识,希望对你有一定的参考价值。
导语
什么是WSGI协议?WSGI的作用?
WSGI
WSGI协议主要分为Server(服务器)和Application(应用程序)两部分:
- Server(服务器):从客户端接收请求,将请求传给应用程序处理,然后将应用程序处理后返回的响应,发送给客户端;
- Application(应用程序):接收从WSGI服务器发送的请求,处理请求,并将处理后的响应结果返回给服务器;
APPlication(应用程序)
def make_app(environ, start_response):
headers = [("Content-type", "text/html")]
status = "200 OK"
start_response(status, headers)
return [bHello, World]
备注:
- environ变量是包含了环境信息的字典;
- start_response也是一个可调用对象,设置响应请求的状态码和响应头;
- 参数名称不一定要求是environ,start_response,要求服务器传入的是位置参数而非关键字参数;
Server(服务器)
from wsgiref.simple_server import make_server
with make_server("", 8000, make_app) as httpd:
print("Server on port 8000......")
httpd.serve_forever()
备注:
- 创建一个WSGI服务器,监听8000端口,指定make_app函数处理请求;
- serve_forever轮询等待请求,直到shutdown()请求;
模拟Get/Post请求解析
GET请求解析:
# -*- coding: utf-8 -*-
from wsgiref.simple_server import make_server
from urllib.parse import parse_qs
def application(environ, start_response):
# 判断是否请求方式是否为GET
headers = [("Content-Type", "text/html")]
method = environ[REQUEST_METHOD]
if method != "GET":
status = "405 Method Not Allowed"
start_response(status, headers)
html = b"405 Method Not Allowed"
return [html]
# 判断请求路径是否合法
path = environ[PATH_INFO]
if path not in ["/hello", "/"]:
status = "404 Not Found"
start_response(status, headers)
html = b"404"
return [html]
status = "200 OK"
start_response(status, headers)
d = parse_qs(environ[QUERY_STRING])
name = d.get("name", [])
if name:
name = name[0]
html = b" Hello, %s , Welcome to my website." % name.encode("utf8")
else:
html = b" Hello, World."
return [html]
with make_server("", 8000, application) as httpd:
print("Server on 8000 Port......")
httpd.serve_forever()
备注:
- 检查environ字典中的REQUEST_METHOD,判断请求方式,如果请求方式不为GET,返回405状态页面;
- 检查environ字典中的PATH_INFO,判断请求路径是否合法,当路径不在预设的列表中,则返回404状态页面;
- 通过parse_qs解析environ字典中的QUER_STRING字符串,判断能否获取对应的请求参数name;
Post请求解析:
# -*- coding: utf-8 -*-
from wsgiref.simple_server import make_server
from cgi import parse_qs
from faker import Faker
import json
def application(environ, start_response):
f = Faker()
wsgi_input = environ["wsgi.input"]
try:
content_length = int(environ.get("CONTENT_LENGTH", 0))
except (ValueError):
content_length = 0
request_body = wsgi_input.read(content_length)
request_json = json.loads(request_body.decode("utf8"))
status = "200 OK"
headers = [("Content-Type", "application/json")]
start_response(status, headers)
name = request_json.get("name", "")
user = "name": name, "address": f.address(), "email": f.email()
text = json.dumps(user)
return [text.encode("utf8")]
with make_server("", 8000, application) as httpd:
print("Server on port 8000....")
httpd.serve_forever()
备注:
- 模拟POST请求提交json数据,获取提交的json数据需要通过environ字典中的wsgi.input文件,而读取该文件则首先需要获取文件的长度CONTENT_LENGTH;
- 将读取到请求数据,通过json解码成字典,再获取到对应key值,这里通过faker伪造数据模拟通过name查询数据库的过程;
- 最后将得到的信息组成字典,通过json编码成字符串,返回给前端;
- 这里没有对请求方式,请求路径,请求数据是否合法进行校验,单纯的测试POST请求流程;
总结
Flask框架
# -*- coding: utf-8 -*-
from flask import Flask, request, jsonify
from faker import Faker
app = Flask(__name__)
@app.route("/", methods=["GET"])
def index():
name = request.args.get("name", "")
if name:
return fHello name, Welcom to my Website.
else:
return <h1>Hello,World
@app.route("/hello", methods=["POST"])
def hello():
data = request.json
name = data.get("name", "")
if not name:
response =
"ret_code": 500,
"ret_info": "name 不能为空。"
return jsonify(response)
else:
f = Faker()
response =
"name": name,
"email": f.email(),
"address": f.address()
return jsonify(response)
if __name__ == "__main__":
app.run("0.0.0.0", port=5000, debug=True)
备注:
- 这里处理对应两个URL,分别对应上述WSGI接口解析GET/POST请求;
- 这里面Flask框架通过使用装饰器,将URL和函数关联起来,这样的处理方式既简洁又方便,这样只用关注处理函数中代码逻辑即可;
- 后期可以分析Flask实现WSGI接口的源码,这里按下不表;
参考
WSGI规范(PEP3333)
wsgiref模块官方文档:
WSGI教程:
以上是关于浅析WSGI协议的主要内容,如果未能解决你的问题,请参考以下文章