開發與維運

WSGI服務器的介紹

本文來自於千鋒教育在阿里雲開發者社區學習中心上線課程《Python入門2020最新大課》,主講人姜偉。

WSGI服務器的介紹

WSGI接口定義非常簡單,它只要求Web開發者實現一個函數,就可以響應HTTP請求。我們來看一個最簡單的Web版本的“Hello, web!”:

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return '<h1>Hello, web!</h1>'

上面的application()函數就是符合WSGI標準的一個HTTP處理函數,它接收兩個參數:

  • environ:一個包含所有HTTP請求信息的dict對象;
  • start_response:一個發送HTTP響應的函數。

在application()函數中,調用:

start_response('200 OK', [('Content-Type', 'text/html')])

就發送了HTTP響應的Header,注意Header只能發送一次,也就是隻能調用一次start_response()函數。start_response()函數接收兩個參數,一個是HTTP響應碼,一個是一組list表示的HTTP Header,每個Header用一個包含兩個str的tuple表示。

通常情況下,都應該把Content-Type頭髮送給瀏覽器。其他很多常用的HTTP Header也應該發送。

然後,函數的返回值'<h1>Hello, web!</h1>'將作為HTTP響應的Body發送給瀏覽器。

有了WSGI,我們關心的就是如何從environ這個dict對象拿到HTTP請求信息,然後構造HTML,通過start_response()發送Header,最後返回Body。

整個application()函數本身沒有涉及到任何解析HTTP的部分,也就是說,底層代碼不需要我們自己編寫,我們只負責在更高層次上考慮如何響應請求就可以了。

application()函數怎麼調用?如果我們自己調用,兩個參數environ和start_response我們沒法提供,返回的str也沒法發給瀏覽器。

所以application()函數必須由WSGI服務器來調用。有很多符合WSGI規範的服務器,我們可以挑選一個來用。但是現在,我們只想儘快測試一下我們編寫的application()函數真的可以把HTML輸出到瀏覽器,所以,要趕緊找一個最簡單的WSGI服務器,把我們的Web應用程序跑起來。

而Python內置了一個WSGI服務器,這個模塊叫wsgiref,它是用純Python編寫的WSGI服務器的參考實現。所謂“參考實現”是指該實現完全符合WSGI標準,但是不考慮任何運行效率,僅供開發和測試使用。
示例:

from wsgiref.simple_server import make_server


# demo_app 需要兩個參數
# 第 0 個參數,表示環境(電腦的環境;請求路徑相關的環境)
# 第 1 個參數,是一個函數,用來返回響應頭
# 這個函數需要一個返回值,返回值是一個列表
# 列表裡只有一個元素,是一個二進制,表示返回給瀏覽器的數據
def demo_app(environ, start_response):
    # environ是一個字典,保存了很多的數據
    # 其中重要的一個是 PATH_INFO能夠獲取到用戶的訪問路徑
    start_response('200 OK', [('Content-Type', 'text/html;charset=utf8')])
    return ['hello'.encode('utf8')]  # 瀏覽器顯示的內容


if __name__ == '__main__':
    # demo_app 是一個函數,用來處理用戶的請求
    httpd = make_server('', 8000, demo_app)
    sa = httpd.socket.getsockname()
    print("Serving HTTP on", sa[0], "port", sa[1], "...")

    # 代碼的作用是打開電腦的瀏覽器,並在瀏覽器裡輸入 http://localhost:8000/xyz?abc
    # import webbrowser
    # webbrowser.open('http://localhost:8000/xyz?abc')

    # 處理一次請求
    # httpd.handle_request()
    httpd.serve_forever()  # 服務器在後臺一致運行

自定義 WSGI服務器

from wsgiref.simple_server import make_server


def demo_app(environ, start_response):
    # environ是一個字典,保存了很多數據
    # 其中最重要的是 PATH_INFO 能夠獲取到用戶的訪問路徑
    path = environ['PATH_INFO']
    print('path= {}'.format(path))
    start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ('sss', 'dddd')])
    return ['你好'.encode('utf8')]


if __name__ == '__main__':
    httpd = make_server('', 8080, demo_app)
    sa = httpd.socket.getsockname()
    print("Serving HTTP on", sa[0], "port", sa[1], "...")
    httpd.serve_forever()

image.png

配套視頻

Leave a Reply

Your email address will not be published. Required fields are marked *