美文网首页
Flask中的响应(response)

Flask中的响应(response)

作者: 黄智勇atTAFinder | 来源:发表于2016-09-05 22:13 被阅读0次

    目录

    • Flask中的Response.
    • 一些特殊的响应.

    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()开始分析. 我们假设整个过程没有异常发生.

        def wsgi_app(self, environ, start_response):
                ...
                try:
                   # 此处获得response.
                    response = self.full_dispatch_request()
                ...
                # 返回response调用后的结果.
                return response(environ, start_response)
                ...
    

    在full_dispatch_request()中:

        def full_dispatch_request(self):
            ...
                if rv is None:
                    rv = self.dispatch_request()
                    # 设置print语句,用于查看rv的值.
                    # 对于示例程序,rv的值为'***Saltriver***'
                    print('rv--->', rv)
            ...
            response = self.make_response(rv)
            response = self.process_response(response)
            ...
            return response
    

    下面我们看self.make_response(rv), make_response文的档说道,rv值可以有4种类型,其中就包括str类型的字符串,其他暂时忽略不管,先分析示例程序中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对rv进行包装(wrap).
                    rv = self.response_class(rv, headers=headers,
                                             status=status_or_headers)
                    headers = status_or_headers = None
                ...
            ...
            return rv
    

    response_class是如何对rv进行包装的呢?可查看werkzeug官方文档5.4节Response. 文档说, In reality, response objects are nothing more than glorified WSGI applications. 实际上,response对象不过是一个遵循WSGI标准的应用而已. 也就是说,我们甚至可以调用它.调用它时,传入什么参数呢? environ和start_response.
    回到full_dispatch_request()中,对于process_response(response),主要做两件事情,调用after_request_functions和设置Cookies, 以此对response做最后的处理.示例程序没有实质性process-response. 最后,返回response(environ, start_response)! 下面来仔细研究研究.

        def run(self, host=None, port=None, debug=None, **options):
            ...
            try:
                # self为一个Flask实例.
                run_simple(host, port, self, **options)
            finally:
                ...
    

    在app.run()里,会调用run_simple函数.我们可以在werkzeug.serving中查看.

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

    在run_simple()中, 我们会调用make_server(...).serve_forever(), 假设make_server返回的是BaseWSGIServer. 在WSGIRequestHandler中,重点分析run_wsgi()函数.下面看其中的execute函数,因为app(environ, start_response)就在其中执行.

            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
    

    由于我们在Flask.wsgi_app(...)返回一个是一个response对象,传入execute函数的app,也就是response对象.

        # 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的任务就是设置了WSGIRequestHandler中run_wsgi中的headers_set变量:

    headers_set[:] = [status, response_headers]
    

    而在run_wsgi中的write(data)函数中, 在向wfile写入data之前,会先写入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()
    

    下面是一些留给我自己思考问题(但还没有解决的问题):

    • WSGI接口为什么要这样设计?
    • app_iter为什么是iterable的?
      ... ...
      准备再重新读一遍PEP333. _

    Part2


    相关文章

      网友评论

          本文标题:Flask中的响应(response)

          本文链接:https://www.haomeiwen.com/subject/eyxlettx.html