歡迎光臨
每天分享高質量文章

如何理解 Python Web 開發?

作者:俞坤

原文:https://www.yukunweb.com/2018/2/understand-python-web/

因為 python程式碼的優雅美觀且易於維護這一特點,越來越多的人選擇使用 Python做Web開發。而 Python的 Web框架百花齊放,目前比較流行的框架有大包大攬的 Django,小巧靈活的 Flask、 Bottle,還有效能高效的非同步框架 Tornado、 sanic。這麼多框架只要選擇一個,閱讀他的檔案,就可以很輕鬆的搭建一個 web app,完全不需要去管他實現的原理。

本篇文章意在對一個web開發做一個梳理。

前端網頁三劍客

我們開啟瀏覽器輸入一個網址 yukunweb.com,然後就看到了瀏覽器給我們顯示的頁面,這個時候開啟瀏覽器開發者工具,點選 Network,掃清頁面,會看到下方的請求的 url,點選 Response,就可以看到伺服器傳回給瀏覽器的 html檔案資訊了。如果複製 Response響應的內容,儲存為 index.html並且在瀏覽器開啟,依然可以看到首頁的內容,但是似乎缺少了一些頁面的樣式和功能。

這是因為當瀏覽器接收到首頁的 HTML原始碼後,它會根據 HTML的規則去顯示頁面,然後再根據 HTML裡的連結,自動傳送HTTP請求給伺服器,拿到相應的圖片,和 JavaScript、 CSS等資源,最終顯示出一個完整的頁面。所以我們會在 Network下麵能看到很多額外的以 .js, .css等字尾的請求了。

其實我們看到的頁面就是瀏覽器按照 HTML的規則,展示給我們的。 HTML告訴瀏覽器那裡是導航,那裡是主欄,那裡是側欄。而這些資訊如何顯示,或者是顯示的樣式,就是 CSS檔案的功勞。至於比如導航的下拉隱藏上拉顯示就是 JavaScript的作用。

如果想要做Web開發,就一定得熟悉 HTML、 CSS、 JavaScript三劍客的知識,這裡推薦W3school的前端教程,也是我學習前端的地方:W3school

客戶端和伺服器通訊

理解了前段三劍客,就知道如何去寫一個網頁。那麼從我們在瀏覽器的位址列輸入 URL,到 Web頁面呈現出來到底經歷了什麼。

如圖,一般這種透過傳送請求獲取伺服器資源的Web瀏覽器,都可以稱為客戶端(client)。首先傳送一個請求(request)給伺服器,大多是以GET請求方式訪問,伺服器接收到你的請求,然後取到請求的資源,傳回給客戶端。

伺服器和客戶端之間交流是怎麼進行的呢,伺服器是怎麼理解客戶端的請求的呢。這裡就需要一種協議規範,就是HTTP(HyperText Transfer Protocol,超文字傳輸協議)。可以說, Web是建立在 HTTP協議上通訊的。

如圖,仍然是之前的例子,開啟瀏覽器訪問 yukunweb.com,開啟瀏覽器開發者工具,點選圖中標記的選項卡(記得點view parsed),可以看到客戶端發給伺服器的請求頭前兩行。

  1. GET / HTTP/1.1

  2. Host: www.yukunweb.com

第一行開頭的GET表示請求訪問伺服器的型別,稱為方法(method)。隨後的字元 /指明瞭請求訪問的資源物件,即請求URI。最後的 HTTP/1.1,即HTTP的版本號,用來提示客戶端使用的 HTTP協議功能。

綜上所述,第一行請求內容的意思是:請求訪問某臺 HTTP伺服器上的 /(首頁)頁面資源。所以第二行的 Host表示請求的域名也就是伺服器所在地址。

如圖,如果是 POST請求的話,不僅會有請求頭部資訊,還有一個 Form Data的請求物體內容。

接收到請求的伺服器呢,他會將請求內容的處理結果以響應的形式傳回,看圖中的第一行:

開頭的部分仍然是伺服器對應的 HTTP版本,緊接著的 200 OK表示請求的處理結果的狀態碼 (status code) 和原因短語。 200狀態碼就表示響應成功,常見的 404表示訪問錯誤, 500表示伺服器響應錯誤。這裡的 OK是沒有固定的規則的,你也可以讓他傳回 GOOD啥的。

下一行是伺服器資訊,本站用的是 Nginx伺服器,在下一行顯示了建立響應的日期時間。在下一行的 Content-Type表示內容的型別,客戶端會依賴他判斷響應的內容是網頁還是音訊,圖片等型別。

這裡只是簡單的介紹了 HTTP協議,即是客戶端與伺服器之間的通訊協議。如果想要深入瞭解推薦閱讀《HTTP權威指南》。

WSGI

如果你瀏覽一個地址 http://www.yukunweb.com/search-result/?keywords=音樂,你會訪問到本站的音樂關鍵詞的搜尋結果。我們知道客戶端傳送請求給伺服器,那麼伺服器是怎麼拿到資源的呢。其實這是交給後端執行的應用傳回的,好比你抓取一個頁面到獲取到資訊,這些邏輯的處理肯定是我們的程式再跑。

但是,接收並且解析客戶端的 HTTP請求在傳送 HTTP響應這些底層操作,後端的程式肯定是不會去處理的。所以,要想只專註於Web業務邏輯,還需要一個伺服器和 web應用之間的嫁接層————WSGI。

什麼是WSGI(Web Server Gateway Interface)?

WSGI翻譯過來就是Web伺服器閘道器介面。他只是一個規範,定義了 Web伺服器如何與 Python應用程式進行互動,使得使用 Python寫的 Web應用程式可以和Web伺服器(nginx/apache)對接起來。

該規範的地址:PEP 333

WSGI是 Python的Web開發的基石,有了它你就有了一切,它存在的目的有兩個:

  • 描述 Web 伺服器如何與 Web 應用程式互動(將客戶端請求傳給應用程式),

  • 描述 Web 應用程式如何處理請求和如何傳回資料給伺服器。

由於 Python內建的標準庫裡有一個 WSGI庫 wsgiref,我們基於他來寫一個體現 WSGI目的的例子:

  1. from wsgiref.simple_server import make_server

  2. def application(environ, start_response):

  3.    status = '200 OK'

  4.    response_essay-headers = [('Content-type', 'text/html')]

  5.    start_response(status, response_essay-headers)

  6.    body = 'Hello, {name} !!!'.format(name=environ['PATH_INFO'][1:] or 'WSGI')

  7.    return [body.encode('utf-8')]

  8. app = make_server('', 8000, application)

  9. app.serve_forever()

執行程式,如果沒有報錯,此時開啟瀏覽器輸入地址 127.0.0.1:8000和 127.0.0.1:8000/GuTianle,就可以看到程式傳回的頁面了。如圖:

我們可以看到一個請求,他的入口只需要一個 WSGI的處理函式。因為所有的請求資訊都包含在 environ中,這樣我們就可以根據這些資訊去傳回不同的資料。

引數:

  • environ:字典型別,存放了所有和客戶端相關的資訊。如果想知道他裡面有哪些引數,可以更改上面的程式碼在 return 行上面加一個 for k, v in environ.items()的迴圈,打印出字典裡的所有引數。

  • startresponse:一個可呼叫物件,接收兩個必選引數和一個可選引數:

    • status: 一個字串,表示 HTTP 響應狀態字串,如 200,404

    • responseessay-headers: 一個串列,包含有如下形式的元組:(essay-headername, essay-headervalue),用來表示 HTTP 響應的 essay-headers ,如('Content-type', 'text/html')

    • exc_info(可選): 用於出錯時,伺服器需要傳回給瀏覽器的資訊

傳回:一個可迭代物件, 伺服器透過遍歷這個可迭代物件可以獲得body的全部內容,內容可以是 html也可以是 json

這裡簡單的介紹了 WSGI是什麼,乾什麼。如果理解了 WSGI,那麼寫一個 Python的Web框架就很簡單了。這也是為什麼 Python有成百上千web框架的原因。

實現基於WSGI的框架

上面我們理解了 WSGI是乾什麼的,那麼我們基於它實現一個簡單的 web框架可以說輕而易舉了。

  1. from wsgiref.simple_server import make_server

  2. class Application(object):

  3.    def __init__(self, environ, start_response):

  4.        self.start_response = start_response

  5.        self.path = environ['PATH_INFO']

  6.    def __iter__(self):

  7.        if self.path == '/':

  8.            status = '200 OK'

  9.            response_essay-headers = [('Content-type', 'text/html')]

  10.            self.start_response(status, esponse_essay-headers)

  11.            yield 'Hello,World!'.encode('utf-8')

  12.        elif self.path == '/wsgi':

  13.            status = '200 OK'

  14.            response_essay-headers = [('Content-type', 'text/html')]

  15.            self.start_response(status, response_essay-headers)

  16.            yield 'Hello,WSGI!'.encode('utf-8')

  17.        else:

  18.            status = '404 NOT FOUND'

  19.            response_essay-headers = [('Content-type', 'text/html')]

  20.            self.start_response(status, response_essay-headers)

  21.            yield '404 NOT FOUND'.encode('utf-8')

  22. if __name__ == "__main__":

  23.    app = make_server('127.0.0.1', 8000, Application)

  24.    print('Serving HTTP on port 8000...')

  25.    app.serve_forever()

這個 Application類只不過是對 WSGI又做了一層簡單的封裝而已,由於上面說過 WSGI函式傳回的是一個可以迭代物件,所以需要實現一個iter方法,裡面控制了客戶端的請求路由並且傳回不同的輸出。

當然如果你想擴充套件成一個像樣的框架還需要考慮很多,比如像 flask那樣方便的路由系統,還有對於使用者請求方式的處理等等。總之是個很需要折騰的過程,好比 flask0.1版本去掉註釋也就 200 多行,而如今最新版本。。。


●編號428,輸入編號直達本文

●輸入m獲取文章目錄

推薦↓↓↓

Web開發

更多推薦18個技術類微信公眾號

涵蓋:程式人生、演演算法與資料結構、駭客技術與網路安全、大資料技術、前端開發、Java、Python、Web開發、安卓開發、iOS開發、C/C++、.NET、Linux、資料庫、運維等。

贊(0)

分享創造快樂

© 2024 知識星球   網站地圖