wsgi:web server gateway interface
CS: ip主机间路由, port进入主机后找进程。
发明www之后
BS:: ip主机间路由, port进入主机后找进程。
解析http请求, 理解URL
解析出请求URL中的PATH, 映射(路由), 找到资源内容
包装成http响应报文返回
WSGI Server(httpd内嵌wsgi 或 uwsgi 或 gunicron), 一个动态页面,必须遵守WSGI协议规范处理。静态页面,磁盘加载响应。 app不是server,是函数,所以wsgi server和app一定在同一个服务器。
WSGI协议规定:
接收请求
来的请求 request 转换为 environ,字典。
之后调用app(environ, start_response), start_response 处理响应状态码和首部。
app返回前, app内部必须调用start_response处理响应状态码和首部
app返回值是响应正文,没有响应状态和首部。
app是遵循wsgi协议的,python实现有flask, django, tornado.
django/flask实现
def app(x,y): # 定义的形参 # 省略10万行: path映射 y(status, [('key', 'value')]) # 调用实参, 处理响应 return ['abc', 'xyz']; # 返回可迭代对象
后期nginx动静分离
静态不由wsgi server处理, nginx, sendfile优化。
动态,qps抗不住。动少,静多。动多了mysql抗不住
python 3.8有新的语法; python 3.6/3.7比较成熟的版本;
准备python3.8项目
pythonprint(f'加载到 {__name__}')
from socketserver import ThreadingTCPServer
from socketserver import StreamRequestHandler
def app(e,s): #environ, start_response Django
# 省略10万行
s('200 OK',[('Content-Type', 'text/html; charset=utf-8')]) # start_response
return [b'abc',b'xyz']
def start_response(): # 难
# 制作headers
pass
class WsgiHandler(StreamRequestHandler): # setup/handler/finish
def handle(self):
# self.request socket , self.server, self.client_address
# self.request.makefile => wfile wb rfile rb
data = self.request.recv(1024) # 请求报文
# data => {}
environ = parse(data) # 请求报文 封装成字典。难
ret = app(environ, start_response) # 实参, 调用app,返回响应体
# server中要把头和身体拼接并返回响应报文格式
firstline = '200 OK HTTP/1.1' # start_response() 完成
headers = "'Content-Type': 'text/html; charset=utf-8'" # start_response() 完成
header = (firstline + '\r\n' + headers + '\r\n\r\n').encode() # start_response() 完成
body = b"".join(ret).decode()
self.request.send(header + body) # 响应
server = ThreadingTCPServer( ('127.0.0.1', 8080), WsgiHandler)
print(f'加载结束=== {__name__}')
有难度:
所以使用以下的方法,只需要app(environ, start_response)函数定义
print(f'加载到 {__name__}') # ref 参考,不能用于生产环境 from wsgiref.simple_server import make_server, demo_app # 把dmeo_app拷贝过来 def demo_app(environ,start_response): from io import StringIO stdout = StringIO() print("Hello world!", file=stdout) print(file=stdout) h = sorted(environ.items()) for k,v in h: print(k,'=',repr(v), file=stdout) start_response("200 OK", [('Content-Type','text/plain; charset=utf-8')]) return [stdout.getvalue().encode("utf-8")] server = make_server('127.0.0.1',8080, demo_app) print(f'加载结束=== {__name__}')
简化
print(f'加载到 {__name__}') # ref 参考,不能用于生产环境 from wsgiref.simple_server import make_server, demo_app # 把dmeo_app拷贝过来 def demo_app(environ,start_response): start_response("200 OK", [('Content-Type','text/plain; charset=utf-8')]) return [b'abc',b'xyz'] server = make_server('127.0.0.1',8080, demo_app) server.serve_forever() print(f'加载结束=== {__name__}')
除了标头的首行和content-type, 都是WSGI Server的start_reponse完成。
wsgi server实现有: uwsgi, gunicorn. 只需要告诉他app(django flask), 我们只管app, 传递environ, environ就是wsgi解析的请求报文。
内部原理看前面, nginx+wsgi
print(f'加载到 {__name__}') # ref 参考,不能用于生产环境 from wsgiref.simple_server import make_server, demo_app html =""" <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>test page</title> </head> <body> <h2 style="color: red;">welcome to magedu -- {}</h2> </body> </html> """.format(8888).encode() def fn(): with open('1.html','r',encoding='utf-8') as fb: data = fb.read() # {} x = 123 # 来自数据库 # return data.format(x).encode() # 基于文件动态生成 return html # 直接动态生成 # 把dmeo_app拷贝过来 def demo_app(environ,start_response): content = fn() start_response("200 OK", [('Content-Type','text/html; charset=utf-8')]) # 发header return [content] # 返回内容 server = make_server('127.0.0.1',8080, demo_app) server.serve_forever() print(f'加载结束=== {__name__}')
本文作者:mykernel
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!