上一篇: 根據不同的請求傳回不同的内容| 手把手教你入門Python之一百一十二 下一篇: WSGI不同路徑傳回不同内容| 手把手教你入門Python之一百一十四 本文來自于千鋒教育在阿裡雲開發者社群學習中心上線課程 《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()
