一起寫一個 Web 服務器(2)

還記得嗎?在本系列第一部分我問過你:“怎樣在你的剛完成的WEB服務器下運行 Django 應用、Flask 應用和 Pyramid 應用?在不單獨修改服務器來適應這些不同的WEB框架的情況下。”往下看,來找出答案。

過去,你所選擇的一個Python Web框架會限制你選擇可用的Web服務器,反之亦然。如果框架和服務器設計的是可以一起工作的,那就很好:

但是,當你試着結合沒有設計成可以一起工作的服務器和框架時,你可能要面對(可能你已經面對了)下面這種問題:

基本上,你只能用可以在一起工作的部分,而不是你想用的部分。

那麼,怎樣確保在不修改Web服務器和Web框架下,用你的Web服務器運行不同的Web框架?答案就是Python Web服務器網關接口(或者縮寫爲WSGI,讀作“wizgy”)。

WSGI允許開發者把框架的選擇和服務器的選擇分開。現在你可以真正地混合、匹配Web服務器和Web框架了。例如,你可以在Gunicorn或者Nginx/uWSGI或者Waitress上面運行Django,Flask,或Pyramid。真正的混合和匹配喲,感謝WSGI服務器和框架兩者都支持:

就這樣,WSGI成了我在本系列第一部分和本文開頭重複問的問題的答案。你的Web服務器必須實現WSGI接口的服務器端,所有的現代Python Web框架已經實現 了WSGI接口的框架端了,這就讓你可以不用修改服務器代碼,適應某個框架。

現在你瞭解了Web服務器和WEb框架支持的WSGI允許你選擇一對兒合適的(服務器和框架),它對服務器和框架的開發者也有益,因爲他們可以專注於他們特定的領域,而不是越俎代庖。其他語言也有相似的接口:例如,Java有Servlet API,Ruby有Rack。

一切都還不錯,但我打賭你會說:“秀代碼給我看!” 好吧,看看這個漂亮且簡約的WSGI服務器實現:

它明顯比本系列第一部分中的服務器代碼大,但爲了方便你理解,而不陷入具體細節,它也足夠小了(只有150行不到)。上面的服務器還做了別的事 – 它可以運行你喜歡的Web框架寫的基本的Web應用,可以是Pyramid,Flask,Django,或者其他的Python WSGI框架。

不信?自己試試看。把上面的代碼保存成webserver2.py或者直接從Github上下載。如果你不帶參數地直接運行它,它就會報怨然後退出。

它真的想給Web框架提供服務,從這開始有趣起來。要運行服務器你唯一需要做的是安裝Python。但是要運行使用Pyramid,Flask,和Django寫的應用,你得先安裝這些框架。一起安裝這三個吧。我比較喜歡使用virtualenv。跟着以下步驟來創建和激活一個虛擬環境,然後安裝這三個Web框架。

此時你需要創建一個Web應用。我們先拿Pyramid開始吧。保存以下代碼到保存webserver2.py時相同的目錄。命名爲pyramidapp.py。或者直接從Github上下載:

現在你已經準備好用完全屬於自己的Web服務器來運行Pyramid應用了:

剛纔你告訴你的服務器從python模塊‘pyramidapp’中加載可調用的‘app’,現在你的服務器準備好了接受請求然後轉發它們給你的Pyramid應用。目前應用只處理一個路由:/hello 路由。在瀏覽器裏輸入http://localhost:8888/hello地址,按回車鍵,觀察結果:

你也可以在命令行下使用‘curl’工具來測試服務器:

檢查服務器和curl輸出了什麼到標準輸出。

現在弄Flask。按照相同的步驟。

保存以上代碼爲flaskapp.py或者從Github上下載它。然後像這樣運行服務器:

現在在瀏覽器裏輸入http://localhost:8888/hello然後按回車:

再一次,試試‘curl’,看看服務器返回了一條Flask應用產生的消息:

服務器也能處理Django應用嗎?試試吧!儘管這有點複雜,但我還是推薦克隆整個倉庫,然後使用djangoapp.py,它是GitHub倉庫的一部分。以下的源碼,簡單地把Django ‘helloworld’ 工程(使用Django的django-admin.py啓動項目預創建的)添加到當前Python路徑,然後導入了工程的WSGI應用。

把以上代碼保存爲djangoapp.py,然後用你的Web服務器運行Django應用:

輸入下面的地址,然後按回車鍵:

雖然你已經做過兩次啦,你還是可以再在命令行測試一下,確認一下,這次是Django應用處理了請求。

你試了吧?你確定服務器可以和這三個框架一起工作吧?如果沒試,請試一下。閱讀挺重要,但這個系列是關於重建的,也就是說,你要自己動手。去動手試試吧。別擔心,我等你喲。你必須試下,最好呢,你親自輸入所有的東西,確保它工作起來像你期望的那樣。

很好,你已經體驗到了WSGI的強大:它可以讓你把Web服務器和Web框架結合起來。WSGI提供了Python Web服務器和Python Web框架之間的一個最小接口。它非常簡單,在服務器和框架端都可以輕易實現。下面的代碼片段展示了(WSGI)接口的服務器和框架端:

以下是它如何工作的:

  • 1.框架提供一個可調用的’應用’(WSGI規格並沒有要求如何實現)
  • 2.服務器每次接收到HTTP客戶端請求後,執行可調用的’應用’。服務器把一個包含了WSGI/CGI變量的字典和一個可調用的’start_response’做爲參數給可調用的’application’。
  • 3.框架/應用生成HTTP狀態和HTTP響應頭,然後把它們傳給可調用的’start_response’,讓服務器保存它們。框架/應用也返回一個響應體。
  • 4.服務器把狀態,響應頭,響應體合併到HTTP響應裏,然後傳給(HTTP)客戶端(這步不是(WSGI)規格里的一部分,但它是後面流程中的一步,爲了解釋清楚我加上了這步)

以下是接口的視覺描述: 

目前爲止,你已經瞭解了Pyramid,Flask,和Django Web應用,你還了解了實現了WSGI規範服務器端的服務器代碼。你甚至已經知道了不使用任何框架的基本的WSGI應用代碼片段。

問題就在於,當你使用這些框架中的一個來寫Web應用時,你站在一個比較高的層次,並不直接和WSGI打交道,但我知道你對WSGI接口的框架端好奇,因爲你在讀本文。所以,咱們一起寫個極簡的WSGI Web應用/Web框架吧,不用Pyramid,Flask,或者Django,然後用你的服務器運行它:

再次,保存以上代碼到wsgiapp.py文件,或者直接從GitHub上下載,然後像下面這樣使用你的Web服務器運行應用:

輸入下面地址,敲回車。你應該就看到下面結果了:

在你學習怎樣寫一個Web服務器時,你剛剛寫了一個你自己的極簡的WSGI Web框架!棒極啦。

現在,讓我們回頭看看服務器傳輸了什麼給客戶端。以下就是使用HTTP客戶端調用Pyramid應用時生成的HTTP響應: 

這個響應跟你在本系列第一部分看到的有一些相近的部分,但也有一些新東西。例如,你以前沒見過的4個HTTP頭:Content-Type, Content-Length, Date, 和Servedr。這些頭是Web服務器生成的響應應該有的。雖然他們並不是必須的。頭的目的傳輸HTTP請求/響應的額外信息。

現在你對WSGI接口瞭解的更多啦,同樣,以下是帶有更多信息的HTTP響應,這些信息表示了哪些部件產生的它(響應): 

我還沒有介紹’environ’字典呢,但它基本上就是一個Python字典,必須包含WSGI規範規定的必要的WSGI和CGI變量。服務器在解析請求後,從HTTP請求拿到了字典的值,字典的內容看起來像下面這樣: 

Web框架使用字典裏的信息來決定使用哪個視圖,基於指定的路由,請求方法等,從哪裏讀請求體,錯誤寫到哪裏去,如果有的話。

現在你已經創建了你自己的WSGI Web服務器,使用不同的Web框架寫Web應用。還有,你還順手寫了個簡單的Web應用/Web框架。真是段難忘的旅程。咱們簡要重述下WSGI Web服務器必須做哪些工作才能處理髮給WSGI應用的請求吧:

  • 首先,服務器啓動並加載一個由Web框架/應用提供的可調用的’application’
  • 然後,服務器讀取請求
  • 然後,服務器解析它
  • 然後,服務器使用請求的數據創建了一個’environ’字典
  • 然後,服務器使用’environ’字典和’start_response’做爲參數調用’application’,並拿到返回的響應體。
  • 然後,服務器使用調用’application’返回的數據,由’start_response’設置的狀態和響應頭,來構造HTTP響應。
  • 最終,服務器把HTTP響應傳回給戶端。 

這就是全部啦。現在你有了一個可工作的WSGI服務器,它可以處理使用像Django,Flask,Pyramid或者 你自己的WSGI框架這樣的兼容WSGI的Web框架寫的基本的Web應用。最優秀的地方是,服務器可以在不修改代碼的情況下,使用不同的Web框架。

在你離開之前,還有個問題請你想一下,“該怎麼做才能讓服務器同一時間處理多個請求呢?”

保持關注,我會在本系列第三部分秀給你看實現它的一種方式。歡呼!

順便說下,我在寫一本書《一起構建WEB服務器:第一步》,它解釋了從零開始寫一個基本的WEB服務器,還更詳細地講解了我上面提到的話題。訂閱郵件組來獲取關於書籍和發佈時間和最近更新。

轉載:http://python.jobbole.com/81523/

發佈了0 篇原創文章 · 獲贊 3 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章