Flask中的響應(yīng)(response)

目錄

  • Flask中的Response.
  • 一些特殊的響應(yīng).

Part1: Flask中的Response


示例程序1
from flask import Flask 

app = Flask(__name__)

@app.route('/')
def index():
    return '***Saltriver***'

if __name__ == '__main__':
    app.run()

仍然從Flask.wsgi_app()開(kāi)始分析. 我們假設(shè)整個(gè)過(guò)程沒(méi)有異常發(fā)生.

    def wsgi_app(self, environ, start_response):
            ...
            try:
               # 此處獲得response.
                response = self.full_dispatch_request()
            ...
            # 返回response調(diào)用后的結(jié)果.
            return response(environ, start_response)
            ...

在full_dispatch_request()中:

    def full_dispatch_request(self):
        ...
            if rv is None:
                rv = self.dispatch_request()
                # 設(shè)置print語(yǔ)句,用于查看rv的值.
                # 對(duì)于示例程序屹徘,rv的值為'***Saltriver***'
                print('rv--->', rv)
        ...
        response = self.make_response(rv)
        response = self.process_response(response)
        ...
        return response

下面我們看self.make_response(rv), make_response文的檔說(shuō)道短绸,rv值可以有4種類型,其中就包括str類型的字符串薛耻,其他暫時(shí)忽略不管辑舷,先分析示例程序中rv為字符串的類型.

    def make_response(self, rv):

        status_or_headers = headers = None
        ...

        if not isinstance(rv, self.response_class):
            # 如果rv為text_type類型.
            if isinstance(rv, (text_type, bytes, bytearray)):
                # 用response_class對(duì)rv進(jìn)行包裝(wrap).
                rv = self.response_class(rv, headers=headers,
                                         status=status_or_headers)
                headers = status_or_headers = None
            ...
        ...
        return rv

response_class是如何對(duì)rv進(jìn)行包裝的呢捕传?可查看werkzeug官方文檔5.4節(jié)Response. 文檔說(shuō), In reality, response objects are nothing more than glorified WSGI applications. 實(shí)際上壁公,response對(duì)象不過(guò)是一個(gè)遵循WSGI標(biāo)準(zhǔn)的應(yīng)用而已. 也就是說(shuō)腔寡,我們甚至可以調(diào)用它.調(diào)用它時(shí)洪添,傳入什么參數(shù)呢垦页? environ和start_response.
回到full_dispatch_request()中,對(duì)于process_response(response)干奢,主要做兩件事情痊焊,調(diào)用after_request_functions和設(shè)置Cookies, 以此對(duì)response做最后的處理.示例程序沒(méi)有實(shí)質(zhì)性process-response. 最后,返回response(environ, start_response)! 下面來(lái)仔細(xì)研究研究.

    def run(self, host=None, port=None, debug=None, **options):
        ...
        try:
            # self為一個(gè)Flask實(shí)例.
            run_simple(host, port, self, **options)
        finally:
            ...

在app.run()里忿峻,會(huì)調(diào)用run_simple函數(shù).我們可以在werkzeug.serving中查看.

    def inner():
        make_server(hostname, port, application, threaded,
                    processes, request_handler,
                    passthrough_errors, ssl_context).serve_forever()

在run_simple()中, 我們會(huì)調(diào)用make_server(...).serve_forever(), 假設(shè)make_server返回的是BaseWSGIServer. 在WSGIRequestHandler中薄啥,重點(diǎn)分析run_wsgi()函數(shù).下面看其中的execute函數(shù),因?yàn)閍pp(environ, start_response)就在其中執(zhí)行.

        def execute(app):
            application_iter = app(environ, start_response)
            try:
                for data in application_iter:
                    write(data)
                if not headers_sent:
                    write(b'')
            finally:
                if hasattr(application_iter, 'close'):
                    application_iter.close()
                application_iter = None

由于我們?cè)贔lask.wsgi_app(...)返回一個(gè)是一個(gè)response對(duì)象逛尚,傳入execute函數(shù)的app,也就是response對(duì)象.

    # Werkzeug/wrappers.py/Class.BaseResponse
    def __call__(self, environ, start_response):
     
        app_iter, status, headers = self.get_wsgi_response(environ)
        start_response(status, headers)
        return app_iter

start_response的任務(wù)就是設(shè)置了WSGIRequestHandler中run_wsgi中的headers_set變量:

headers_set[:] = [status, response_headers]

而在run_wsgi中的write(data)函數(shù)中, 在向wfile寫入data之前垄惧,會(huì)先寫入status和response_headers.

        def write(data):
            assert headers_set, 'write() before start_response'
            if not headers_sent:  # <---注意此處.
                status, response_headers = headers_sent[:] = headers_set
                try:
                    code, msg = status.split(None, 1)
                except ValueError:
                    code, msg = status, ""
                self.send_response(int(code), msg)  # <---注意此處.
                header_keys = set()
                for key, value in response_headers:
                    self.send_header(key, value)
                    key = key.lower()
                    header_keys.add(key)
                if 'content-length' not in header_keys:
                    self.close_connection = True
                    self.send_header('Connection', 'close')
                if 'server' not in header_keys:
                    self.send_header('Server', self.version_string())
                if 'date' not in header_keys:
                    self.send_header('Date', self.date_time_string())
                self.end_headers()  # <---注意此處.

            assert type(data) is bytes, 'applications must write bytes'
            self.wfile.write(data)  # <---注意此處.
            self.wfile.flush()

下面是一些留給我自己思考問(wèn)題(但還沒(méi)有解決的問(wèn)題):

  • WSGI接口為什么要這樣設(shè)計(jì)?
  • app_iter為什么是iterable的绰寞?
    ... ...
    準(zhǔn)備再重新讀一遍PEP333. _

Part2


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末到逊,一起剝皮案震驚了整個(gè)濱河市铣口,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌觉壶,老刑警劉巖脑题,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異铜靶,居然都是意外死亡叔遂,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門争剿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)已艰,“玉大人,你說(shuō)我怎么就攤上這事蚕苇×ú簦” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵捆蜀,是天一觀的道長(zhǎng)疮丛。 經(jīng)常有香客問(wèn)我,道長(zhǎng)辆它,這世上最難降的妖魔是什么誊薄? 我笑而不...
    開(kāi)封第一講書人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮锰茉,結(jié)果婚禮上呢蔫,老公的妹妹穿的比我還像新娘。我一直安慰自己飒筑,他們只是感情好片吊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著协屡,像睡著了一般俏脊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上肤晓,一...
    開(kāi)封第一講書人閱讀 51,155評(píng)論 1 299
  • 那天爷贫,我揣著相機(jī)與錄音,去河邊找鬼补憾。 笑死漫萄,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的盈匾。 我是一名探鬼主播腾务,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼削饵!你這毒婦竟也來(lái)了岩瘦?” 一聲冷哼從身側(cè)響起未巫,我...
    開(kāi)封第一講書人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎担钮,沒(méi)想到半個(gè)月后橱赠,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體尤仍,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡箫津,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了宰啦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片苏遥。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖赡模,靈堂內(nèi)的尸體忽然破棺而出田炭,到底是詐尸還是另有隱情,我是刑警寧澤漓柑,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布教硫,位于F島的核電站,受9級(jí)特大地震影響辆布,放射性物質(zhì)發(fā)生泄漏瞬矩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一锋玲、第九天 我趴在偏房一處隱蔽的房頂上張望景用。 院中可真熱鬧,春花似錦惭蹂、人聲如沸伞插。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)媚污。三九已至,卻和暖如春廷雅,著一層夾襖步出監(jiān)牢的瞬間耗美,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工榜轿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留幽歼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓谬盐,卻偏偏與公主長(zhǎng)得像甸私,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子飞傀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容