成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

如何自定義Flask中的響應(yīng)類(譯文)

ruicbAndroid / 2971人閱讀

摘要:在使用自定義響應(yīng)類的應(yīng)用中,和無(wú)法知道自定義類的細(xì)節(jié),所以它們使用標(biāo)準(zhǔn)響應(yīng)類來(lái)創(chuàng)建響應(yīng)。有了這個(gè)自定義響應(yīng)類,任何滿足格式要求的文檔都會(huì)自動(dòng)被標(biāo)記為內(nèi)容類型,而其他響應(yīng)則會(huì)繼續(xù)獲得默認(rèn)的內(nèi)容類型。


譯文鏈接:編程派

原文鏈接:Flask Web Development作者的博客

有翻譯或理解不對(duì)的地方,望大家指正!

Flask框架中的響應(yīng)類,命名很貼切,叫Response。不過Flask應(yīng)用中很少直接調(diào)用這個(gè)類。而是將其作為路由函數(shù)所返回響應(yīng)數(shù)據(jù)的內(nèi)部容器,容器里還包含了用于創(chuàng)建HTTP響應(yīng)的其他信息。

但是沒多少人知道,F(xiàn)lask框架其實(shí)允許應(yīng)用將默認(rèn)的響應(yīng)類,替換為自定義類。這就給了我們研究小竅門的機(jī)會(huì)。在本文中,我將展示如何利用Flask的這個(gè)特性,簡(jiǎn)化你的代碼。

Flask中的響應(yīng)類是如何工作的?

大部分應(yīng)用并不直接使用Flask中的響應(yīng)類(Response class),但這并不是說(shuō)這個(gè)類沒有用武之地;實(shí)際上,F(xiàn)lask會(huì)為每個(gè)請(qǐng)求創(chuàng)建響應(yīng)對(duì)象。那么,它是如何實(shí)現(xiàn)的呢?

Flask用來(lái)處理請(qǐng)求的函數(shù)返回時(shí),響應(yīng)周期就開始了。在網(wǎng)絡(luò)應(yīng)用中,路由通常最后會(huì)調(diào)用render_template函數(shù),渲染引用的模板文件,將其作為字符串返回:

@app.route("/index")
def index():
    # ...
    return render_template("index.html")

但是,你可能也知道,F(xiàn)lask的路由函數(shù)可以選擇額外返回兩個(gè)值,這兩個(gè)值將被分別設(shè)為HTTP狀態(tài)碼和自定義的HTTP響應(yīng)標(biāo)頭:

@app.route("/data")
def index():
    # ...
    return render_template("data.json"), 201, {"Content-Type": "application/json"}

在上面的例子中,狀態(tài)碼被設(shè)為201,取代了Flask默認(rèn)的200,即請(qǐng)求被成功處理的狀態(tài)碼。這個(gè)例子還定義了內(nèi)容類型標(biāo)頭(Content-Type header),表明HTTP響應(yīng)中包含JSON數(shù)據(jù),因?yàn)槿绻悴幻鞔_設(shè)置內(nèi)容類型的話,F(xiàn)lask會(huì)默認(rèn)設(shè)置為HTML。

上面的例子介紹了HTTP響應(yīng)的三個(gè)基本組成部分,即數(shù)據(jù)或正文、狀態(tài)碼和標(biāo)頭。Flask的應(yīng)用實(shí)例擁有一個(gè)make_response函數(shù),可以接受路由函數(shù)的返回值(可以是單個(gè)值,也可以是有1-3個(gè)值的元組),并將其填入響應(yīng)對(duì)象(Response object)中。

你可以通過Python控制臺(tái)會(huì)話(console session),看看整個(gè)過程。首先創(chuàng)建一個(gè)虛擬環(huán)境,并安裝Flask,然后開啟Python會(huì)話,并輸入下面的代碼:

>>> from flask import Flask
>>> app = Flask(__name__)
>>> app.make_response("Hello, World")

>>> app.make_response(("Hello, World", 201))

這里,我創(chuàng)建了一個(gè)簡(jiǎn)單的Flask應(yīng)用實(shí)例,之后調(diào)用了make_response()方法創(chuàng)建響應(yīng)類對(duì)象。第一次調(diào)用時(shí),我傳了一個(gè)字符串作為參數(shù),所以響應(yīng)對(duì)象中使用了默認(rèn)的狀態(tài)碼和標(biāo)頭。第二次調(diào)用時(shí),我傳入了有兩個(gè)值的元組,強(qiáng)制返回了非默認(rèn)的狀態(tài)碼。注意,第二次調(diào)用時(shí)使用了兩個(gè)括號(hào),里層的括號(hào)將字符串和狀態(tài)碼包在了元組中。由于make_response()函數(shù)只接受一個(gè)參數(shù),所以必須要這樣做。

Flask在創(chuàng)建了代表路由函數(shù)返回值的響應(yīng)對(duì)象(Response object)之后,還會(huì)做一些處理。包括將響應(yīng)對(duì)象傳入自定義的after_request處理程序(handlers),在這一步,應(yīng)用還有有機(jī)會(huì)插入或修改標(biāo)頭、更改正文或狀態(tài)碼,如果愿意的話,甚至是啟用嶄新的的響應(yīng)對(duì)象取而代之。最后,F(xiàn)lask會(huì)獲取最終的響應(yīng)對(duì)象,渲染成HTTP響應(yīng),并發(fā)送給客戶端。

Flask中的響應(yīng)類

我們來(lái)看看響應(yīng)類中最有趣的特性。下面的類定義,展示了我眼中這個(gè)類所具備的靈活屬性和方法:

class Response:
    charset = "utf-8"
    default_status = 200
    default_mimetype = "text/html"

    def __init__(self, response=None, status=None, headers=None,
                 mimetype=None, content_type=None, direct_passthrough=False):
        pass

    @classmethod
    def force_type(cls, response, environ=None):
        pass

注意,如果你去翻閱Flask的源碼,是找不到上述類定義的。Flask中的Response類,實(shí)際上衍生自Werkzeug庫(kù)中的一個(gè)同名類。而Werzeug中的Response類繼承的是BaseResponse類,這個(gè)類中就包含了上述定義。

charsetdefault_statusdefault_mimetype這三個(gè)類屬性定義了相應(yīng)的默認(rèn)值。如果任何一個(gè)默認(rèn)值不適用你的應(yīng)用,那么你可以創(chuàng)建Response類的子類,定義你自己的默認(rèn)值,而不必在每一個(gè)響應(yīng)對(duì)象中設(shè)置自定義值。例如,如果你的應(yīng)用是一個(gè)所有的路由均返回XML格式數(shù)據(jù)的API接口,你就可以在自定義的類中,將default_mimetype改為application/xml,這樣Flask就會(huì)默認(rèn)返回XML響應(yīng)。稍后你會(huì)看到如何實(shí)現(xiàn)。

這里,我不會(huì)詳細(xì)介紹__init__構(gòu)造函數(shù)(你可以閱讀Werkzeug的文檔),但請(qǐng)注意,F(xiàn)lask響應(yīng)對(duì)象中的三個(gè)重要元素,即響應(yīng)正文、狀態(tài)碼和標(biāo)頭,是作為參數(shù)傳入的。在子類中,構(gòu)造函數(shù)可以改變創(chuàng)建響應(yīng)的相應(yīng)規(guī)則。

響應(yīng)類中的force_type()類方法,是唯一比較復(fù)雜,但又很重要的元素。有時(shí)候,Werkzeug或是Flask需要自行創(chuàng)建響應(yīng)對(duì)象,比如出現(xiàn)應(yīng)用錯(cuò)誤,并需要將其返回給客戶端時(shí)。在這種情況下,響應(yīng)對(duì)象不是應(yīng)用提供的,而是由框架創(chuàng)建的。在使用自定義響應(yīng)類的應(yīng)用中,F(xiàn)lask和Werkzeug無(wú)法知道自定義類的細(xì)節(jié),所以它們使用標(biāo)準(zhǔn)響應(yīng)類來(lái)創(chuàng)建響應(yīng)。響應(yīng)類中的force_type()方法,被設(shè)計(jì)為可以接受不同響應(yīng)類的實(shí)例,并會(huì)將其轉(zhuǎn)換成自身的格式。

我敢肯定,你一定被force_type()方法的描述搞糊涂了。說(shuō)白了,就是如果Flask碰到了一個(gè)不是其期望的響應(yīng)對(duì)象,就會(huì)使用該方法進(jìn)行轉(zhuǎn)換。我下面要講的第三個(gè)使用場(chǎng)景,就利用了這個(gè)特點(diǎn),讓Flask的路由函數(shù)返回諸如字典、列表或者是其他任何自定義對(duì)象,作為請(qǐng)求的響應(yīng)對(duì)象。

好了,理論就講這么多了。接下來(lái),我來(lái)告訴大家如何應(yīng)用上面有關(guān)響應(yīng)類的小技巧。準(zhǔn)備好了嗎?

使用自定義的響應(yīng)類

到現(xiàn)在為止,我確定你也會(huì)認(rèn)為:在部分有趣的場(chǎng)景下,使用自定義的響應(yīng)類是有利的。在給出實(shí)際例子之前,我想告訴你在Flask中設(shè)置并使用自定義的響應(yīng)類是多么的簡(jiǎn)單。請(qǐng)看下面的這個(gè)例子:

from flask import Flask, Response

class MyResponse(Response):
    pass

app = Flask(__name__)
app.response_class = MyResponse

# ...

在上面的代碼中,我定義了一個(gè)名叫MyResponse的自定義響應(yīng)類。通常,自定義響應(yīng)類會(huì)增加或修改默認(rèn)類的行為,所以一般都會(huì)通過創(chuàng)建Flask中Response類的子類來(lái)實(shí)現(xiàn)。要想讓Flask使用自定義類,我只需要設(shè)置app.response_class即可。

Flask類中的response_class是一個(gè)類屬性,所以我們可以稍微修改上面的例子,創(chuàng)建一個(gè)設(shè)置了自定義響應(yīng)類的Flask子類:

from flask import Flask, Response

class MyResponse(Response):
    pass

class MyFlask(Flask)
    response_class = MyResponse

app = MyFlask(__name__)

# ...
例1:更改響應(yīng)對(duì)象的默認(rèn)值

第一個(gè)例子極其簡(jiǎn)單。假設(shè)你的應(yīng)用中大部分或全部端點(diǎn)(endpoints)都返回的是XML。對(duì)于這樣的應(yīng)用,將默認(rèn)的內(nèi)容類型設(shè)置為application/xml是合理的。可以通過下面這個(gè)僅有兩行代碼的響應(yīng)類輕松實(shí)現(xiàn):

class MyResponse(Response):
    default_mimetype = "application/xml"

容易,對(duì)吧?如果將其設(shè)為應(yīng)用的默認(rèn)響應(yīng)類,那么你在編寫返回XML的函數(shù)時(shí),就不用擔(dān)心忘記設(shè)置內(nèi)容類型了。舉個(gè)例子:

@app.route("/data")
def get_data():
    return """

    John Smith

"""

上面這個(gè)路由使用的是默認(rèn)響應(yīng)類,其內(nèi)容類型會(huì)被設(shè)置為text/html,因?yàn)槟鞘悄J(rèn)類型。使用自定義響應(yīng)類,可以免去你在所有XML路由的返回語(yǔ)句中,額外加上標(biāo)頭的麻煩。另外,如果有的路由需要其他的內(nèi)容類型,你仍可以替換掉默認(rèn)值,就像對(duì)待一般的響應(yīng)類一樣。

@app.route("/")
def index():
    return "

Hello, World!

", {"Content-Type": "text/html"}
例2:自動(dòng)決定內(nèi)容類型

下一個(gè)例子更復(fù)雜一點(diǎn)。假設(shè)我們的應(yīng)用中HTML路由與XML路由的數(shù)量差不多,所以按照第一個(gè)例子的做法就不行了,因?yàn)椴还苣氵x用哪種默認(rèn)類型,都會(huì)有一半的路由需要替換內(nèi)容類型。

更好的解決辦法,則是創(chuàng)建一個(gè)能夠通過分析響應(yīng)文本,決定正確的內(nèi)容類型的響應(yīng)類。下面的這個(gè)類實(shí)現(xiàn)了該功能:

class MyResponse(Response):
    def __init__(self, response, **kwargs):
        if "mimetype" not in kwargs and "contenttype" not in kwargs:
            if response.startswith("

在這個(gè)簡(jiǎn)單的例子中,我首先確保響應(yīng)對(duì)象中沒有明確設(shè)置內(nèi)容類型。然后,我檢查響應(yīng)的正文是否以開頭,是的話就意味著數(shù)據(jù)是XML文檔格式。如果兩個(gè)條件同時(shí)成立,我會(huì)在傳入父類構(gòu)造函數(shù)的參數(shù)中,插入XML內(nèi)容類型。

有了這個(gè)自定義響應(yīng)類,任何滿足XML格式要求的文檔都會(huì)自動(dòng)被標(biāo)記為XML內(nèi)容類型,而其他響應(yīng)則會(huì)繼續(xù)獲得默認(rèn)的內(nèi)容類型。而且,在所有的類中,我仍然可以在必要時(shí)聲明內(nèi)容類型。

例3:自動(dòng)返回JSON響應(yīng)

最后一個(gè)例子,針對(duì)的是利用Flask創(chuàng)建API接口時(shí)常見的一個(gè)小問題。API接口通常返回的是JSON凈負(fù)荷(JSON Payload,這就要求你使用jsonify()函數(shù)將Python字典類型轉(zhuǎn)換成JSON數(shù)據(jù),并且還得在響應(yīng)對(duì)象中將內(nèi)容類型設(shè)置為JSON內(nèi)容類型。請(qǐng)看下面這個(gè)例子:

@app.route("/data")
def get_data():
    return jsonify({"foo": "bar"})

問題是,每個(gè)返回JSON的路由都需要這樣處理,那么對(duì)接口數(shù)量眾多的的API來(lái)說(shuō),你就得大量重復(fù)調(diào)用jsonify()函數(shù)。從代碼可讀性角度來(lái)講,你按照下面的方式處理是不是更好?

@app.route("/data")
def get_data():
    return {"foo": "bar"}

下面是一個(gè)支持使用上述語(yǔ)法的自定義響應(yīng)類,它不會(huì)影響應(yīng)用中使用其他內(nèi)容類型的路由正常工作:

class MyResponse(Response):
    @classmethod
    def force_type(cls, rv, environ=None):
        if isinstance(rv, dict):
            rv = jsonify(rv)
        return super(MyResponse, cls).force_type(rv, environ)

這個(gè)例子需要稍微解釋一下,因?yàn)楸容^復(fù)雜。Flask僅認(rèn)可一小部分的類型,作為路由函數(shù)能夠返回的有效響應(yīng)類型?;旧?,你可以返回任意與字符串和二進(jìn)制相關(guān)的類型(strunicode、bytesbytearray)。如果你喜歡,甚至可以返回一個(gè)已經(jīng)創(chuàng)建好的響應(yīng)對(duì)象。如果你返回的是字符串或二進(jìn)制類型,F(xiàn)lask會(huì)發(fā)現(xiàn)這些是響應(yīng)類知道如何處理的類型,并會(huì)將你返回的數(shù)據(jù)直接傳入響應(yīng)類的構(gòu)造函數(shù)。

但是,如果你返回的是不支持的類型,比如說(shuō)上述例子中的字典,會(huì)發(fā)生什么情況?如果返回的響應(yīng)類型不是Flask預(yù)期的,那么Flask就會(huì)默認(rèn)它是未知響應(yīng)對(duì)象,不會(huì)以其為參數(shù)創(chuàng)建響應(yīng)對(duì)象了,而是使用響應(yīng)類的force_type()類方法,強(qiáng)制轉(zhuǎn)換未知類型。上面的例子中,響應(yīng)子類替換了該方法,但僅僅是通過調(diào)用jsonify()進(jìn)行轉(zhuǎn)換,之后就會(huì)讓基類接手處理,就好像什么都沒發(fā)生一樣。

是個(gè)很好的竅門吧?尤其是這樣做不會(huì)影響其他響應(yīng)的正常工作。對(duì)于返回正常響應(yīng)類型的路由,該子類不會(huì)做任何處理,所有的調(diào)用請(qǐng)求會(huì)全部傳入父類中。

結(jié)語(yǔ)

我希望本文能夠幫助大家更好地理解FLask中響應(yīng)對(duì)象的工作原理。如果你知道其他使用Flask響應(yīng)類的小竅門,請(qǐng)務(wù)必與我分享!

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/44191.html

相關(guān)文章

  • [譯]使用Flask實(shí)現(xiàn)RESTful API

    摘要:中使用類字典對(duì)象來(lái)獲取請(qǐng)求頭信息,使用獲取請(qǐng)求數(shù)據(jù),如果發(fā)送類型是,則可以使用來(lái)獲取數(shù)據(jù)。響應(yīng)使用類處理響應(yīng)。認(rèn)證使用下面的代碼可以處理。 原創(chuàng)譯文,如需轉(zhuǎn)載,請(qǐng)聯(lián)系譯者。 我的簡(jiǎn)書博客:nummy 原文地址:Implementing a RESTful Web API with Python & Flask 簡(jiǎn)介 首先,安裝Flask pip install flask 閱讀這篇文章...

    oogh 評(píng)論0 收藏0
  • Flask學(xué)習(xí)

    摘要:服務(wù)器會(huì)根據(jù)將請(qǐng)求交給相應(yīng)的程序處理。函數(shù)稱為視圖函數(shù)。無(wú)參數(shù)當(dāng)訪問網(wǎng)站根域名時(shí),會(huì)執(zhí)行函數(shù),返回值的結(jié)果會(huì)在網(wǎng)頁(yè)中顯示。。而返回特殊狀態(tài)碼可在返回值中添加,代碼如下返回特殊狀態(tài)碼鍵值對(duì)形式后的鍵值對(duì)由提供對(duì)象處理。 Web框架 Web框架是構(gòu)建Web應(yīng)用的一種方式。盡管現(xiàn)在很多語(yǔ)言如PHP、Java都能開發(fā)Web應(yīng)用,這些語(yǔ)言也都有相應(yīng)成熟的Web框架,但是請(qǐng)求處理是這些Web框架的...

    OnlyLing 評(píng)論0 收藏0
  • flask基礎(chǔ)之一

    摘要:最經(jīng)典的就是了暫時(shí)性重定向的狀態(tài)碼是,表示頁(yè)面暫時(shí)性被跳轉(zhuǎn),比如訪問一個(gè)需要權(quán)限的網(wǎng)址,如果當(dāng)前用戶沒有登錄,應(yīng)該重定向到登錄頁(yè)面。作為額外的消息頭如果以上的條件都不滿足,會(huì)假設(shè)返回值是一個(gè)合法的應(yīng)用程序,并通過轉(zhuǎn)換成一個(gè)請(qǐng)求對(duì)象。 flask基礎(chǔ)之一 hello world #從flask這個(gè)包中導(dǎo)入Flask這個(gè)類 #Flask這個(gè)類是項(xiàng)目的核心,以后的很多操作都是基于這個(gè)類的對(duì)象...

    archieyang 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<