wsgi與web應用的骨架

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()

在上邊的程序了裏:

  1. init(self):定義socket通訊的服務器端,用來監聽端口、接收數據、返回數據。
  2. serve_forever(self):調用app,生成相應的http報文,在通過socket返回。
  3. 瀏覽器:接收服務器返回的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!
發佈了61 篇原創文章 · 獲贊 6 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章