目錄
- 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. _