欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Django 源碼WSGI剖析過(guò)程詳解

 更新時(shí)間:2019年08月05日 10:44:13   作者:搗亂小子  
這篇文章主要介紹了Django 源碼WSGI剖析過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

前言

python 作為一種腳本語(yǔ)言, 已經(jīng)逐漸大量用于 web 后臺(tái)開(kāi)發(fā)中, 而基于 python 的 web 應(yīng)用程序框架也越來(lái)越多, Bottle, Django, Flask 等等.

在一個(gè) HTTP 請(qǐng)求到達(dá)服務(wù)器時(shí), 服務(wù)器接收并調(diào)用 web 應(yīng)用程序解析請(qǐng)求, 產(chǎn)生響應(yīng)數(shù)據(jù)并返回給服務(wù)器. 這里涉及了兩個(gè)方面的東西: 服務(wù)器(server)和應(yīng)用程序(application). 勢(shì)必要有一個(gè)合約要求服務(wù)器和應(yīng)用程序都去遵守, 如此按照此合約開(kāi)發(fā)的無(wú)論是服務(wù)器還是應(yīng)用程序都會(huì)具有較大的普遍性. 而這就好像在計(jì)算機(jī)通信的早期, 各大公司都有屬于自己的通信協(xié)議, 如此只會(huì)讓市場(chǎng)雜亂無(wú)章, 寧愿只要一種通信協(xié)議.

而針對(duì) python 的合約是 WSGI(Python Web Server Gateway Interface). 具體的規(guī)定見(jiàn) PEP 333.

實(shí)習(xí)的時(shí)候一直使用 Django, 下面是結(jié)合 Django 學(xué)習(xí) WSGI 的筆記.

application/應(yīng)用程序

在應(yīng)用程序一方面, 必須提供下面的方法:

def simple_app(environ, start_response):
  """可能是最簡(jiǎn)單的處理了"""
  status = '200 OK'
  response_headers = [('Content-type', 'text/plain')]
  start_response(status, response_headers)
  return ['Hello world!\n'] # 返回結(jié)果必須可迭代

除了方法以外, 還可以用實(shí)現(xiàn)了 __call__ 的類實(shí)現(xiàn).

它會(huì)被服務(wù)器調(diào)用, 在這里 environ 是一個(gè)字典, 包含了環(huán)境變量, REQUEST_METHOD,SCRIPT_NAME,QUERY_STRING 等; start_response 是一個(gè)回調(diào)函數(shù), 會(huì)在 simple_app 中被調(diào)用, 主要用來(lái)開(kāi)始響應(yīng) HTTP. start_response 原型大概是這樣:

def start_response(status, response_headers, exc_info=None):
  ...
  return write # 返回這 write 函數(shù) 只是為了兼容之前的 web 框架, 新的框架根本用不到.

參數(shù)有 status 即狀態(tài)碼; response_headers HTTP 頭, 可以修改; exc_info 是與錯(cuò)誤相關(guān)的信息, 在產(chǎn)生相應(yīng)數(shù)據(jù)過(guò)程中可能發(fā)生錯(cuò)誤, 這時(shí)需要更新 HTTP 頭部, 通過(guò)再次調(diào)用 start_response 可以實(shí)現(xiàn). 因此更為詳盡的實(shí)現(xiàn)寫法可能是這種:

def start_response(status, response_headers, exc_info=None):
  if exc_info:
     try:
       # do stuff w/exc_info here
     finally:
       exc_info = None  # Avoid circular ref.
  return write

Server/服務(wù)器

在服務(wù)器方面, 可以想象最簡(jiǎn)單的工作就是調(diào)用 simple_app(), 然后向客戶端發(fā)送數(shù)據(jù):

result = simple_app(environ, start_response) #名字不一定為 simple_app
try:
  for data in result:
    if data:  # don't send headers until body appears
      write(data)
  if not headers_sent:
    write('')  # send headers now if body was empty
finally:
  if hasattr(result, 'close'):
    result.close()

注意 WSGI 并沒(méi)有事無(wú)巨細(xì)規(guī)定 web 應(yīng)用程序和服務(wù)器內(nèi)部的工作方式, 只是是規(guī)定了它們之間連接的標(biāo)準(zhǔn).

python wsgiref 模塊

下面看看 Django 是如何實(shí)現(xiàn) WSGI 的. Django 其內(nèi)部已經(jīng)自帶了一個(gè)方便本地測(cè)試的小服務(wù)器, 所以在剛開(kāi)始學(xué)習(xí) Django 的時(shí)候并不需搭建 apache 或者 nginx 服務(wù)器. Django 自帶的服務(wù)器基于 python wsgiref 模塊實(shí)現(xiàn), 它自帶的測(cè)試代碼:

# demo_app() 是 application
def demo_app(environ,start_response):
  from StringIO import StringIO
  stdout = StringIO()
  print >>stdout, "Hello world!"
  print >>stdout
  h = environ.items(); h.sort()
  for k,v in h:
    print >>stdout, k,'=', repr(v)
  start_response("200 OK", [('Content-Type','text/plain')])
  return [stdout.getvalue()]

def make_server(
  host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler
):
  """Create a new WSGI server listening on `host` and `port` for `app`"""
  server = server_class((host, port), handler_class)
  server.set_app(app)
  return server

if __name__ == '__main__':
  httpd = make_server('', 8000, demo_app)
  sa = httpd.socket.getsockname()
  print "Serving HTTP on", sa[0], "port", sa[1], "..."
  import webbrowser
  webbrowser.open('http://localhost:8000/xyz?abc')
  httpd.handle_request() # serve one request, then exit

python 的庫(kù)有好多的工具, 這時(shí)可能因?yàn)樾枰脑? 會(huì)生出好多的父類, 為了講明, 根據(jù) wsgiref 模塊和它自帶的測(cè)試用例得出下面的 UML 圖(注意, 這只是 wsgiref, 沒(méi)有涉及 Django):

我讀完這些的時(shí)候已經(jīng)暈了, 確實(shí)是里邊的繼承關(guān)系有些復(fù)雜. 因此, 簡(jiǎn)要的概括了測(cè)試代碼的執(zhí)行關(guān)系:

  • make_server() 中 WSGIServer 類已經(jīng)作為服務(wù)器類, 負(fù)責(zé)接收請(qǐng)求, 調(diào)用 application 的處理, 返回相應(yīng);
  • WSGIRequestHandler 作為請(qǐng)求處理類, 并已經(jīng)配置在 WSGIServer 中;
  • 接著還設(shè)置了 WSGIServer.application 屬性(set_app(app));
  • 返回 server 實(shí)例.
  • 接著打開(kāi)瀏覽器, 即發(fā)起請(qǐng)求. 服務(wù)器實(shí)例 WSGIServer httpd 調(diào)用自身 handle_request() 函數(shù)處理請(qǐng)求. handle_request() 的工作流程如下:請(qǐng)求-->WSGIServer 收到-->調(diào)用 WSGIServer.handle_request()-->調(diào)用 _handle_request_noblock()-->調(diào)用 process_request()-->調(diào)用 finish_request()-->finish_request() 中實(shí)例化 WSGIRequestHandler-->實(shí)例化過(guò)程中會(huì)調(diào)用 handle()-->handle() 中實(shí)例化 ServerHandler-->調(diào)用 ServerHandler.run()-->run() 調(diào)用 application() 這才是真正的邏輯.-->run() 中在調(diào)用 ServerHandler.finish_response() 返回?cái)?shù)據(jù)-->回到 process_request() 中調(diào)用 WSGIServer.shutdown_request() 關(guān)閉請(qǐng)求(其實(shí)什么也沒(méi)做)

ps: 明明 application 是 WSGIServer 的屬性, 為什么會(huì)在 ServerHandler 中調(diào)用? 因?yàn)樵趯?shí)例化 WSGIRequestHandler 的時(shí)候 WSGIServer 把自己搭進(jìn)去了, 所以在 WSGIRequestHandler 中實(shí)例化 ServerHandler 時(shí)候可以通過(guò) WSGIRequestHandler.server.get_app() 得到真正的 application.

總結(jié)

從上面可以得到, 啟動(dòng)服務(wù)器的時(shí)候, 無(wú)論以什么方式都要給它傳遞一個(gè) application(), 是一個(gè)函數(shù)也好, 一個(gè)實(shí)現(xiàn)了 __call__ 的類也好; 當(dāng)請(qǐng)求到達(dá)服務(wù)器的時(shí)候, 服務(wù)器自會(huì)調(diào)用 application(), 從而得到相應(yīng)數(shù)據(jù). 至于, 對(duì)請(qǐng)求的數(shù)據(jù)如何相應(yīng), application() 中可以細(xì)化.

確實(shí), 其中的調(diào)用鏈太過(guò)長(zhǎng), 這期間還沒(méi)有加入 HTTP 頭的分析(提取 Cookie等). 如果只為響應(yīng)一個(gè) "helloworld", 在 WSGIServer.finish_request() 中直接相應(yīng)數(shù)據(jù)就好了, WSGIRequestHandler 和 ServerHandler 類可以直接省去, 而只需要你提供一個(gè) application()! 但事實(shí)上, 并不只是相應(yīng) "helloworld" 那樣簡(jiǎn)單...

關(guān)于 Django 中的 WSGI 如何, 下一節(jié)再說(shuō). Django 源碼剖析從這里開(kāi)始! 我已經(jīng)在 github 備份了 Django 源碼的注釋: Decode-Django, 有興趣的童鞋 fork 吧. 本文結(jié)合 python wsgiref, BaseHTTPServer.py, SocketServer.py 模塊源碼看更好.

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 圖文詳解Python如何導(dǎo)入自己編寫的py文件

    圖文詳解Python如何導(dǎo)入自己編寫的py文件

    有時(shí)候自己寫了一個(gè)py文件,想要把它導(dǎo)入到另一個(gè)py文件里面,所以下面這篇文章主要給大家介紹了關(guān)于Python如何導(dǎo)入自己編寫的py文件的相關(guān)資料,需要的朋友可以參考下
    2021-11-11
  • 對(duì)python 命令的-u參數(shù)詳解

    對(duì)python 命令的-u參數(shù)詳解

    今天小編就為大家分享一篇對(duì)python 命令的-u參數(shù)詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • python多線程實(shí)現(xiàn)動(dòng)態(tài)圖繪制

    python多線程實(shí)現(xiàn)動(dòng)態(tài)圖繪制

    這篇文章主要介紹了python多線程實(shí)現(xiàn)動(dòng)態(tài)圖繪制,文章基于Python的相資料展開(kāi)動(dòng)態(tài)圖的繪制相關(guān)內(nèi)容,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-04-04
  • Python生成隨機(jī)密碼的方法

    Python生成隨機(jī)密碼的方法

    這篇文章主要為大家詳細(xì)介紹了Python生成隨機(jī)密碼的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • python標(biāo)準(zhǔn)庫(kù)ElementTree處理xml

    python標(biāo)準(zhǔn)庫(kù)ElementTree處理xml

    這篇文章主要為大家介紹了python標(biāo)準(zhǔn)庫(kù)ElementTree處理xml的方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • 使用scrapy實(shí)現(xiàn)增量式爬取方式

    使用scrapy實(shí)現(xiàn)增量式爬取方式

    這篇文章主要介紹了使用scrapy實(shí)現(xiàn)增量式爬取方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Pygame實(shí)戰(zhàn)之實(shí)現(xiàn)經(jīng)典外星人游戲

    Pygame實(shí)戰(zhàn)之實(shí)現(xiàn)經(jīng)典外星人游戲

    這篇文章主要介紹了通過(guò)Pygame實(shí)現(xiàn)經(jīng)典的外星人游戲的示例代碼,文中的代碼講解詳細(xì),對(duì)我們了解Pygame有一定的幫助,感興趣的同學(xué)可以試一試
    2022-01-01
  • 輕松掌握Python爬蟲,從入門到精通

    輕松掌握Python爬蟲,從入門到精通

    Python爬蟲學(xué)習(xí)完整版來(lái)了!想成為一名爬蟲高手,掌握數(shù)據(jù)采集的技能嗎?這份指南將帶你從零開(kāi)始,一步步掌握Python爬蟲的各種技巧,讓你輕松獲取海量數(shù)據(jù),需要的朋友可以參考下
    2024-03-03
  • keras實(shí)現(xiàn)調(diào)用自己訓(xùn)練的模型,并去掉全連接層

    keras實(shí)現(xiàn)調(diào)用自己訓(xùn)練的模型,并去掉全連接層

    這篇文章主要介紹了keras實(shí)現(xiàn)調(diào)用自己訓(xùn)練的模型,并去掉全連接層,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-06-06
  • 用python繪制櫻花樹

    用python繪制櫻花樹

    這篇文章主要介紹了如何用python繪制櫻花樹,幫助大家更好的使用python處理圖片,感興趣的朋友可以了解下
    2020-09-09

最新評(píng)論