2022-05-01
devops
00
请注意,本文编写于 719 天前,最后修改于 718 天前,其中某些信息可能已经过时。

目录

wsgi

wsgi:web server gateway interface

CS开发

CS: ip主机间路由, port进入主机后找进程。

  • client: 主动请求
  • server: 响应请求

BS开发

发明www之后

BS:: ip主机间路由, port进入主机后找进程。

  • Browser(渲染引擎,JS引擎): 主动请求, 发基于tcp的http请求(文本), 对http响应解析,渲染成网页; http://www.mykernel.cn:80/index.html
    • www.mykerne.cn 解析为ip, 主机间路由
    • 目标主机,到达 监听80端口的进程
    • 进程处理, /index.html对应磁盘上的文件,打开,读,发给用户
  • www server: 响应请求, html, 磁盘上的文件。open, read 'br' 二进制读取, send
    • 解析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.

01-uwsgi

app 实现

django/flask实现

def app(x,y): # 定义的形参 # 省略10万行: path映射 y(status, [('key', 'value')]) # 调用实参, 处理响应 return ['abc', 'xyz']; # 返回可迭代对象
  1. app(x,y) 即是 app(environ,start_response)
  2. app返回前 start_response(status,[('key', 'value')])
  3. 返回可迭代对象

后期nginx

后期nginx动静分离

静态不由wsgi server处理, nginx, sendfile优化。

动态,qps抗不住。动少,静多。动多了mysql抗不住

wsgi服务器 -- wsgiref

python 3.8有新的语法; python 3.6/3.7比较成熟的版本;

准备python3.8项目

wsgi基于socket server 原理实现过程

image-20220401155218001

python
print(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__}')

有难度:

  • parse, 解析request
  • start_response, 发header

所以使用以下的方法,只需要app(environ, start_response)函数定义

wsgi 简单实现过程

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__}')

image-20220401162426522

除了标头的首行和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 许可协议。转载请注明出处!