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

通過(guò)Python中的CGI接口講解什么是WSGI

 更新時(shí)間:2022年04月20日 11:26:10   作者:Biiigfish  
這篇文章主要為大家通過(guò)Python中的CGI接口及應(yīng)用示例講解什么是WSGI,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

今天在 git.oschina 的首頁(yè)上看到他們推出演示平臺(tái),其中,Python 的演示平臺(tái)支持 WSGI 接口的應(yīng)用。雖然,這個(gè)演示平臺(tái)連它自己提供的示例都跑不起來(lái),但是,它還是成功的勾起了我對(duì) WSGI 的好奇心。一番了解,對(duì)該機(jī)制的認(rèn)識(shí),總結(jié)如下。如有不妥,還望斧正。

為什么是 WSGI?

寫過(guò)網(wǎng)頁(yè)應(yīng)用的各位親,應(yīng)該對(duì) CGI 有了解,我們知道,CGI 的全程是“Common Gateway Interface”,即 “通用 Gateway Interface“。沒(méi)錯(cuò),這里的 WSGI,就是只針對(duì) Python的網(wǎng)頁(yè)應(yīng)用接口“Python Web Server Gateway Interface”。通過(guò)這樣的類比,想必大家對(duì)他的地位就有所了解了。

它只是一個(gè)接口定義:它不負(fù)責(zé)服務(wù)器的實(shí)現(xiàn),也不負(fù)責(zé)網(wǎng)頁(yè)應(yīng)用的實(shí)現(xiàn),它只是一個(gè)兩邊接口方式的約定。所以,它并不是另一個(gè) WEB 應(yīng)用框架。通常意義上的 WEB 應(yīng)用框架,也只相當(dāng)于 WSGI 網(wǎng)頁(yè)應(yīng)用端的一種實(shí)現(xiàn)。

這樣做的好處是?PEP 0333 中的解釋是,為了實(shí)現(xiàn)一個(gè)類似于 Java Servelet 的 API,使得遵循該接口的應(yīng)用擁有更廣泛的適用性。是的,有了該接口,你就不用去考慮,服務(wù)器對(duì) Python 的支持到底是如何實(shí)現(xiàn)——無(wú)論是“ 直接用 Python 實(shí)現(xiàn)的服務(wù)器”,還是“服務(wù)器嵌入 Python”,或者是 “ 通過(guò)網(wǎng)關(guān)接口(CGI, Fastcgi...)”——應(yīng)用程序都有很好的適用性。就像是今天故事的開(kāi)始,我們遇到了云平臺(tái),它提供了對(duì) WSGI 接口的支持,那么,只要應(yīng)用是基于 WSGI 的,那么應(yīng)用就可以直接跑起來(lái)。

此外,WSGI 的設(shè)計(jì),也提供了另外一種可能性,那就是中間件(middleware)。或者說(shuō),我們可以寫一些對(duì) server 和 application 都兼容的模塊,我們可以把他們部署在 Server 端,也可以部署在 Application 端,完成比如緩存、字符編碼轉(zhuǎn)換、根據(jù) url 做應(yīng)用 routing 等功能。這種設(shè)計(jì)模式,是 WSGI 降低了 server 和 application 耦合度之后的產(chǎn)物,同時(shí),它從另一個(gè)角度大大提升了設(shè)計(jì)的靈活性。

WSGI 實(shí)施概略

上一小節(jié),簡(jiǎn)要對(duì) WSGI 做了介紹。這里從 application、server、middleware 三個(gè)角度對(duì) WSGI 稍微進(jìn)行深入,使我們對(duì)它有一個(gè)更具體的印象。

1)Application 端

WSGI 要求,應(yīng)用端必須提供一個(gè)可被調(diào)用的實(shí)體(PEP 0333 使用的是 Object,文檔還特別解釋這有別于Object instance),該實(shí)體可以是:一個(gè)函數(shù)(function)、一個(gè)方法(method)、一個(gè)類(class)、或者是有__call__方法的對(duì)象(Object instance)。

這里有兩個(gè)網(wǎng)頁(yè)應(yīng)用端的實(shí)現(xiàn)示例,一個(gè)是 function object,一個(gè) class object:

def simple_app(environ, start_response):
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers)
    return ['Hello world!\n']

上面的 function 只是直接對(duì)請(qǐng)求直接做了 “200 ok” 回應(yīng),并沒(méi)有處理傳進(jìn)來(lái)的參數(shù) environ——里面是由 WSGI Server 端提供的各種 HTTP 請(qǐng)求參數(shù)。需要特別注意的是,這個(gè)函數(shù)在最后,返回的一個(gè) list(用“[]”包含在內(nèi))以保證結(jié)果的 iterable。下面的 class 類似。

在下面例子中,AppClass 作為應(yīng)用實(shí)體。當(dāng)調(diào)用發(fā)生時(shí),其實(shí)是對(duì) class 進(jìn)行了例化( python 固有特性,可以參考后面 server 端的實(shí)現(xiàn)代碼進(jìn)一步理解),正如我們看到,這次調(diào)用(call)的返回值也是可迭代的——雖然只迭代一次(yield)。

class AppClass:
    def __init__(self, environ, start_response):
        self.environ = environ
        self.start = start_response
    def __iter__(self):
        status = '200 OK'
        response_headers = [('Content-type', 'text/plain')]
        self.start(status, response_headers)
        yield "Hello world!\n"
        """ In fact, the interator ‘ends‘ here because of no more yield field"""

與上面兩種情形不同,使用 object instance 作為應(yīng)用實(shí)體時(shí),需要為類定義添加 __call__ 方法,同時(shí),參考上面使用 function 作為實(shí)體時(shí)情形,__call__ 方法的返回值需為 iterable(比如 return [ something ])。

最后,不管我們的 app 是 function 還是 class, application 都需要處理兩個(gè)參數(shù),而且是兩個(gè)位置相關(guān)的參數(shù)(不是命名參數(shù)),分別是:一個(gè)存放了 CGI 環(huán)境變量的 dictionary object,和一個(gè)可調(diào)用實(shí)體(需要給它三個(gè)位置相關(guān)的參數(shù),兩個(gè)必須,一個(gè)可選)。

其中,可調(diào)用實(shí)體(前例中的 start_response)必須調(diào)用一次,兩個(gè)必須的參數(shù)分別為“ HTTP Response的狀態(tài)(str 類型)“ 和 “HTTP Response Header(list of tuples)“;

一個(gè)可選的參數(shù)exc_info,必須是 Python sys.exc_info() tuple,只有在出錯(cuò)需要顯示錯(cuò)誤信息時(shí)使用。完整調(diào)用:start_response(status, response_headers,exc_info).

2)Server 端

下面是從 PEP 0333 拿來(lái)的一個(gè)簡(jiǎn)單的 WSGI 容器,適用于 Python 作為某 WEB Server 上 CGI 時(shí)的應(yīng)用情形。

import os, sys
def run_with_cgi(application):
    environ = dict(os.environ.items())
    environ['wsgi.input']        = sys.stdin
    environ['wsgi.errors']       = sys.stderr
    environ['wsgi.version']      = (1, 0)
    environ['wsgi.multithread']  = False
    environ['wsgi.multiprocess'] = True
    environ['wsgi.run_once']     = True
    if environ.get('HTTPS', 'off') in ('on', '1'):
        environ['wsgi.url_scheme'] = 'https'
    else:
        environ['wsgi.url_scheme'] = 'http'
    headers_set = []
    headers_sent = []
    def write(data):
        if not headers_set:
             raise AssertionError("write() before start_response()")
        elif not headers_sent:
             # Before the first output, send the stored headers
             status, response_headers = headers_sent[:] = headers_set
             sys.stdout.write('Status: %s\r\n' % status)
             for header in response_headers:
                 sys.stdout.write('%s: %s\r\n' % header)
             sys.stdout.write('\r\n')
        sys.stdout.write(data)
        sys.stdout.flush()
    def start_response(status, response_headers, exc_info=None):
        if exc_info:
            try:
                if headers_sent:
                    # Re-raise original exception if headers sent
                    raise exc_info[0], exc_info[1], exc_info[2]
            finally:
                exc_info = None     # avoid dangling circular ref
        elif headers_set:
            raise AssertionError("Headers already set!")
        headers_set[:] = [status, response_headers]
        return write
    result = application(environ, start_response)
    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()

上面的容器,大概實(shí)現(xiàn)了:

  • a)將 CGI 環(huán)境變量放入 dictionary object (environ)中,供 Application 實(shí)體使用;
  • b)定義了 start_response 方法,供 Application 實(shí)體調(diào)用;
  • c)調(diào)用 application 實(shí)體,對(duì) web 請(qǐng)求進(jìn)行處理;
  • d)將 application 的返回結(jié)果,以及通過(guò) start_response 設(shè)置的 HTTP Response HEADER,寫到 stdout ——像其他 CGI 一樣,實(shí)際上是被發(fā)往網(wǎng)頁(yè)。

3) 作為 middleware

因?yàn)?WSGI 的寬松耦合的特性,我們可以輕松的在 Application 和 Server 之前插入任何的中間插件,在不需要改動(dòng) Server 和 Application 的前提下,實(shí)現(xiàn)一些特殊功能。但是,這種放在 Server 和 Application “中間”的模塊,并不是這里要講的 middleware ;或者,這只能算是一種特殊的 middleware,因?yàn)樗鼉H僅是實(shí)現(xiàn)了 PEP 0333 中 middleware 定義的 Application 側(cè)的功能。這種僅實(shí)施在一側(cè)的 middleware,需要在發(fā)布時(shí),特別的聲明。

PEP 0333 中約定,中間件是一些即可以在 Server 端實(shí)施,又可以在 Application 端實(shí)施的模塊。所以,在設(shè)計(jì)的時(shí)候,對(duì)兩邊的特性都要做適當(dāng)考慮。幸好,WSGI 接口設(shè)計(jì)的足夠簡(jiǎn)單。

class Router():
    def __init__(self):
        self.path_info = {}
    def route(self, environ, start_response):
        application = self.path_info[environ['PATH_INFO']]
        return application(environ, start_response)
    def __call__(self, path):
        def wrapper(application):
            self.path_info[path] = application
        return wrapper
""" The above is the middleware"""
router = Router()
@router('/world')
def world(environ, start_response):
    status = '200 OK'
    output = 'World!'start_response(status, response_headers)  
    return [output] 
@router('/hello') 
def hello(environ, start_response):
    status = '200 OK'
    output = 'Hello'
    response_headers = [('Content-type', 'text/plain'), ('Content-Length', str(len(output)))]
    start_response(status, response_headers)  
    return [output]

簡(jiǎn)單解釋一下:

- 作為 Application 時(shí),我們用 Router 實(shí)例化一個(gè)對(duì)象。然后對(duì) “ PATH-APP “ 進(jìn)行注冊(cè),根據(jù)不同的 PATH,我們要進(jìn)一步選擇哪個(gè) App。接著,就是把 router.route() 喂給 Server ,作為 Application 側(cè)的可調(diào)用實(shí)體。有請(qǐng)求到來(lái)時(shí),根據(jù)已經(jīng)注冊(cè)的 “PATH-APP” 對(duì)選擇應(yīng)用并執(zhí)行。

- Server 端類似,我們要先實(shí)例化并完成注冊(cè)。然后,比如,拿我們上一小節(jié)實(shí)現(xiàn)的 WSGI 容器為例,我們需要修改 result = router.route(environ, start_response),同樣完成了router的功能。

下面是另外一個(gè),實(shí)現(xiàn)了 postprocessor 的一個(gè)例子,在 Application 返回的 HTTP Header 里面再加一個(gè) Header。

def myapp(environ, start_response):
    response_headers = [('content-type', 'text/plain')]
    start_response('200 OK', response_headers)
    return ['Check the headers!']
class Middleware:
    def __init__(self, app):
        self.wrapped_app = app
    def __call__(self, environ, start_response):
        def custom_start_response(status, headers, exc_info=None):
            headers.append(('X-A-SIMPLE-TOKEN', "1234567890"))
            return start_response(status, headers, exc_info)
        return self.wrapped_app(environ, custom_start_response)
app = Middleware(myapp)

這里通過(guò)改寫傳遞給 Application 的實(shí)體,實(shí)現(xiàn)了 postprocess 的目的。

其他資源:

- WSGI 的一些詳細(xì)資料,包括應(yīng)用列表什么的:https://wsgi.readthedocs.io/en/latest/

- 支持 WSGI 的多線程 WEB 服務(wù)器,基于SimpleHttpServer:

http://www.owlfish.com/software/wsgiutils/

-Paste為構(gòu)建以 WSGI 為基礎(chǔ)的 WEB 應(yīng)用程序或框架提供一個(gè)良好的基礎(chǔ)

- 官方的 WSGI 實(shí)現(xiàn)參考:https://pypi.org/project/wsgiref/

- 啄木鳥(niǎo)社區(qū)的 WSGI 中文 wiki:https://wiki.woodpecker.org.cn/moin/WSGI

- 和 Paste 一樣有名的基本架構(gòu):https://pypi.org/project/Pylons/1.0/

- 目前 Python 比較流行的三大 WEB 框架:TurboGears,Django,web2py。+1,代碼在 K 級(jí)別的服務(wù)小框架:webpy。

- 另外三個(gè)據(jù)說(shuō)高性能的 App 開(kāi)發(fā)框架:Falcon、Tornado、Bootle.py.

- 還有個(gè)價(jià)格不錯(cuò)的 vps,恩:https://www.hostwinds.com/

以上就是通過(guò)Python中的CGI接口講解什么是WSGI的詳細(xì)內(nèi)容,更多關(guān)于Python中CGI接口講解WSGI的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 超實(shí)用的 30 段 Python 案例

    超實(shí)用的 30 段 Python 案例

    Python是目前最流行的語(yǔ)言之一,它在數(shù)據(jù)科學(xué)、機(jī)器學(xué)習(xí)、web開(kāi)發(fā)、腳本編寫、自動(dòng)化方面被許多人廣泛使用。這篇文章主要介紹了超實(shí)用的 30 段 Python 案例,需要的朋友可以參考下
    2019-10-10
  • Pytorch數(shù)據(jù)拼接與拆分操作實(shí)現(xiàn)圖解

    Pytorch數(shù)據(jù)拼接與拆分操作實(shí)現(xiàn)圖解

    這篇文章主要介紹了Pytorch數(shù)據(jù)拼接與拆分操作實(shí)現(xiàn)圖解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • Python文本轉(zhuǎn)語(yǔ)音引擎pyttsx3的使用完全指南

    Python文本轉(zhuǎn)語(yǔ)音引擎pyttsx3的使用完全指南

    在開(kāi)發(fā)需要語(yǔ)音輸出功能的應(yīng)用時(shí),文本轉(zhuǎn)語(yǔ)音技術(shù)是一個(gè)非常有用的工具,Python的pyttsx3庫(kù)提供了一個(gè)簡(jiǎn)單且離線的方式來(lái)實(shí)現(xiàn)這一功能,下面小編就來(lái)和大家介紹一下pyttsx3的具體使用吧
    2025-04-04
  • Python解決線性代數(shù)問(wèn)題之矩陣的初等變換方法

    Python解決線性代數(shù)問(wèn)題之矩陣的初等變換方法

    今天小編就為大家分享一篇Python解決線性代數(shù)問(wèn)題之矩陣的初等變換方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • Python3實(shí)現(xiàn)的反轉(zhuǎn)單鏈表算法示例

    Python3實(shí)現(xiàn)的反轉(zhuǎn)單鏈表算法示例

    這篇文章主要介紹了Python3實(shí)現(xiàn)的反轉(zhuǎn)單鏈表算法,結(jié)合實(shí)例形式總結(jié)分析了Python基于迭代算法與遞歸算法實(shí)現(xiàn)的翻轉(zhuǎn)單鏈表相關(guān)操作技巧,需要的朋友可以參考下
    2019-03-03
  • Python遍歷某目錄下的所有文件夾與文件路徑

    Python遍歷某目錄下的所有文件夾與文件路徑

    這篇文章主要介紹了Python遍歷某目錄下的所有文件夾與文件路徑 以及輸出中文亂碼問(wèn)題的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • django項(xiàng)目搭建與Session使用詳解

    django項(xiàng)目搭建與Session使用詳解

    這篇文章主要給大家介紹了關(guān)于django項(xiàng)目搭建與Session使用的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-10-10
  • Pycharm編輯器功能之代碼折疊效果的實(shí)現(xiàn)代碼

    Pycharm編輯器功能之代碼折疊效果的實(shí)現(xiàn)代碼

    這篇文章主要介紹了Pycharm編輯器功能之代碼折疊效果的實(shí)現(xiàn)代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10
  • OpenCV形狀檢測(cè)的示例詳解

    OpenCV形狀檢測(cè)的示例詳解

    本文主要介紹了OpenCV中的形狀檢測(cè),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • Python列表賦值的六種核心方法

    Python列表賦值的六種核心方法

    在Python編程中,列表(list)是最常用的數(shù)據(jù)結(jié)構(gòu)之一,當(dāng)需要復(fù)制或修改列表時(shí),不同的賦值方式會(huì)產(chǎn)生截然不同的性能表現(xiàn),本文將帶您深入探索列表賦值的六種核心方法,通過(guò)實(shí)際性能測(cè)試揭示它們的效率差異,并給出不同場(chǎng)景下的最佳選擇,需要的朋友可以參考下
    2025-04-04

最新評(píng)論