1、WSGI是什麼
wsgi:Web Server Gateway Interface,是一種協議。用於定義Server與app之間的交互方式。
wsgi把應用分成了3個組件:
1. web server:
主要實現:
1.socket通訊服務器端,監聽端口
2.接收、解析http報文
3.讀取服務器端的html文檔,把讀取的html文檔response回瀏覽器,這是靜態服務器,如nginx、Apache
4.調用app,返回app執行結果給瀏覽器。這是動態服務器,如Tomcat。
2. web app
1.一個函數或類的方法
2.遵循固定格式的入口函數_call_()、入參(environ,start_response)、返回值
3. 中間件
1.server與app中間的程序(所以叫中間件)
2.路由
3.流量控制等
ps:
wsgi對web應用的劃分太精闢了,對WebServer的理解、應用、url轉應用調用等場景的理解豁然開朗。
以前只知道Tomcat,按這個概念套用,也更清楚了。
2、舉個例子加深理解
# coding=utf-8
import socket
import sys
class WSGIServer:
def __init__(self):
self.listener=socket.socket()
self.listener.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
self.listener.bind(('0.0.0.0',8080))
self.listener.listen(1)
print('Serving HTTP 0.0.0.0 port 8080')
self.app=None
self.headers_set=None
def set_app(self,application):
self.app=application
##start_response是服務器提供的函數,供app調用
def start_response(self,status,headers):
self.headers_set=[status,headers]
def serve_forever(self):
while True:
listener=self.listener
client_connection,client_address=listener.accept()
##socket服務器端,接收數據,是http協議的報文
request=client_connection.recv(1024)
print(f'request we received:{request}')
method,path,_=request.split(b' ',2)
environ = {
'wsgi.version': (1, 0),
'wsgi.url_scheme': 'http',
'wsgi.input': request,
'wsgi.errors': sys.stderr,
'wsgi.multithread': False,
'wsgi.multiprocess': False,
'wsgi.run_once': False,
'REQUEST_METHOD': method.decode('utf-8'),
'PATH_INFO': path.decode('utf-8'),
'SERVER_NAME': '127.0.0.1',
'SERVER_PORT': '8080',
}
##server調用app,傳入environ(接收到的http報文)和start_response函數
##app內執行傳入的start_response函數,並返回結果http內容
app_result=self.app(environ,self.start_response)
##response和app返回的內容構成整個響應的html
response_status,response_headers=self.headers_set
response=f'HTTP/1.1 {response_status}\r\n'
for header in response_headers:
response+=f'{header[0]}:{header[1]}\r\n'
response+='\r\n'
response=response.encode('utf-8')
for data in app_result:
response+=data
##通過網絡通訊,返回完整的響應http
client_connection.sendall(response)
client_connection.close()
print('!!!!!!!!one request responsed!!!!!!!!')
if __name__=='__main__':
if len(sys.argv)<2:
sys.exit('argv error')
app_path=sys.argv[1]
module,app=app_path.split(':')
module=__import__(module)
app=getattr(module,app)
server=WSGIServer()
server.set_app(app)
server.serve_forever()
在上邊的程序了裏:
- init(self):定義socket通訊的服務器端,用來監聽端口、接收數據、返回數據。
- serve_forever(self):調用app,生成相應的http報文,在通過socket返回。
- 瀏覽器:接收服務器返回的http報文,然後渲染展示。
3、看看http請求和相應報文
對程序的部分內容加深理解。
3.1 請求報文
包括:請求的方法、url、客戶端程序類型等。
瀏覽器自動生成併發送的。
GET / HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
3.2 響應報文
注意遵守固定格式,響應頭包括協議版本、響應編號、響應結果,
然後,與實際內容中間間隔一個空行。
HTTP/1.1 200 OK
Hello, World!