Flask1.1.4 Werkzeug1.0.1 源码分析:请求和响应

um,其实这篇不讲请求,因为请求已经在 上下文解析中讲解过了,这里主要研究响应。

其实之前分析了 Request后,应该可以意识到Response应该是类似的。
下面先看下请求执行过程中和Response相关的代码。

class Flask(_PackageBoundObject):

    def __call__(self, environ, start_response):
    	# 这边
        return self.wsgi_app(environ, start_response)

    def wsgi_app(self, environ, start_response):
        ctx = self.request_context(environ)
        error = None
        try:
            try:
                ctx.push()
                # response 为flask.Response对象
                response = self.full_dispatch_request()
            except Exception as e:
                error = e
                response = self.handle_exception(e)
            except:  # noqa: B001
                error = sys.exc_info()[1]
                raise
            # 此处调用 flask.Response.__call__ 方法 后面具体看
            return response(environ, start_response)
        finally:
            if self.should_ignore_error(error):
                error = None
            ctx.auto_pop(error)
      
    def full_dispatch_request(self):
        self.try_trigger_before_first_request_functions()
        try:
            request_started.send(self)
            rv = self.preprocess_request()
            if rv is None:
            	# rv 就是view_func的返回值
                rv = self.dispatch_request()
        except Exception as e:
            rv = self.handle_user_exception(e)
        # 此方法将view_func的返回值 转换为 flask.Response对象
        return self.finalize_request(rv) 

    def finalize_request(self, rv, from_error_handler=False):
    	# 构建Response对象的具体方法
        response = self.make_response(rv)
        try:
        	# 执行一些hook
            response = self.process_response(response)
            request_finished.send(self, response=response)
        except Exception:
            if not from_error_handler:
                raise
            self.logger.exception(
                "Request finalizing failed with an error while handling an error"
            )
        return response   

	# 注释说的很清楚了  我感觉我没啥好写的 看注释即可
	# 就是基于 view_func返回值的格式 尝试构造一个Response对象并返回
    def make_response(self, rv):
        """Convert the return value from a view function to an instance of
        :attr:`response_class`.
        """

        status = headers = None

        # unpack tuple returns
        # 如果返回的是tuple,会基于约定尝试拆包
        if isinstance(rv, tuple):
            len_rv = len(rv)

            # a 3-tuple is unpacked directly
            if len_rv == 3:
                rv, status, headers = rv
            # decide if a 2-tuple has status or headers
            elif len_rv == 2:
                if isinstance(rv[1], (Headers, dict, tuple, list)):
                    rv, headers = rv
                else:
                    rv, status = rv
            # other sized tuples are not allowed
            else:
                raise TypeError(
                    "The view function did not return a valid response tuple."
                    " The tuple must have the form (body, status, headers),"
                    " (body, status), or (body, headers)."
                )

        # the body must not be None
        if rv is None:
            raise TypeError(
                "The view function did not return a valid response. The"
                " function either returned None or ended without a return"
                " statement."
            )

        # make sure the body is an instance of the response class
        # 这边的response_class就是flask.Response 类
        if not isinstance(rv, self.response_class):
            if isinstance(rv, (text_type, bytes, bytearray)):
                # let the response class set the status and headers instead of
                # waiting to do it manually, so that the class can handle any
                # special logic
                rv = self.response_class(rv, status=status, headers=headers)
                status = headers = None
            elif isinstance(rv, dict):
                rv = jsonify(rv)
            elif isinstance(rv, BaseResponse) or callable(rv):
                # evaluate a WSGI callable, or coerce a different response
                # class to the correct type
                try:
                    rv = self.response_class.force_type(rv, request.environ)
                except TypeError as e:
                    new_error = TypeError(
                        "{e}\nThe view function did not return a valid"
                        " response. The return type must be a string, dict, tuple,"
                        " Response instance, or WSGI callable, but it was a"
                        " {rv.__class__.__name__}.".format(e=e, rv=rv)
                    )
                    reraise(TypeError, new_error, sys.exc_info()[2])
            else:
                raise TypeError(
                    "The view function did not return a valid"
                    " response. The return type must be a string, dict, tuple,"
                    " Response instance, or WSGI callable, but it was a"
                    " {rv.__class__.__name__}.".format(rv=rv)
                )

        # prefer the status if it was provided
        if status is not None:
            if isinstance(status, (text_type, bytes, bytearray)):
                rv.status = status
            else:
                rv.status_code = status

        # extend existing headers with provided headers
        if headers:
            rv.headers.extend(headers)

        return rv

好的,下面来看下Response对象,HTTP格式的返回就是三部分 status,headers, body

# 和request一样没有啥内容,主要功能都是继承来的
class Response(ResponseBase, JSONMixin):

    default_mimetype = "text/html"

# 和 request一样的组合类
class Response(
    BaseResponse,
    ETagResponseMixin,
    WWWAuthenticateMixin,
    CORSResponseMixin,
    ResponseStreamMixin,
    CommonResponseDescriptorsMixin,
):
	pass

class BaseResponse(object):
	# 类属性作为实例属性的默认值
    #: the charset of the response.
    charset = "utf-8"
	
    def __init__(
        self,
        response=None,
        status=None,
        headers=None,
        mimetype=None,
        content_type=None,
        direct_passthrough=False,
    ):
    	# 构建header
        if isinstance(headers, Headers):
            self.headers = headers
        elif not headers:
            self.headers = Headers()
        else:
            self.headers = Headers(headers)
            
        # 构建 response
        if response is None:
            self.response = []
        elif isinstance(response, (text_type, bytes, bytearray)):
        	# str 或者bytes类型的返回值处理
            self.set_data(response)
        else:
            self.response = response

    def set_data(self, value):
        # str类型就encode为bytes
        if isinstance(value, text_type):
            value = value.encode(self.charset)
        else:
            value = bytes(value)
        # 最终的response
        self.response = [value]
        if self.automatically_set_content_length:
            self.headers["Content-Length"] = str(len(value))

	# 此方法对应上面的 response(environ, start_response) 
	# 以wsgi app的形式返回数据
    def __call__(self, environ, start_response):
    	# 仔细看doc
        """Process this response as WSGI application.

        :param environ: the WSGI environment.
        :param start_response: the response callable provided by the WSGI
                               server.
        :return: an application iterator
        """
        # 把当前已有的响应信息 转换为wsgi格式返回
        app_iter, status, headers = self.get_wsgi_response(environ)
        # 响应 status 和 headers
        # start_response 为 WSGI server调用flask_app() 是传入的可调用对象
        start_response(status, headers)
        # 返回一个可迭代对象
        return app_iter

可以看出,最终的response转换为 二进制形式。下面再来看下 Headers类。

class Headers(object):
	# 都在doc里了
    """An object that stores some headers.  It has a dict-like interface
    but is ordered and can store the same keys multiple times.

    This data structure is useful if you want a nicer way to handle WSGI
    headers which are stored as tuples in a list.
    """
    def __init__(self, defaults=None):
    	# 底层是一个 list
        self._list = []
        if defaults is not None:
            if isinstance(defaults, (list, Headers)):
                self._list.extend(defaults)
            else:
                self.extend(defaults)

	# 对应[]或者get()
    def __getitem__(self, key, _get_mode=False):
       	# 在列表中搜索对应的header
        ikey = key.lower()
        for k, v in self._list:
            if k.lower() == ikey:
                return v

总结一下:

  1. 当一个HTTP请求来临时,WSGI server将HTTP格式数据转换为WSGI格式数据,并调用 flask_app(environ, start_response)
  2. flask 开始处理请求时会使用environ来构建flask.Request对象,这样后续view_function 中我们可以通过flask.request从中获取需要的请求信息
  3. 根据environ 路由到具体的view_function执行,并返回
  4. 将view_function的返回转换为flask.Response对象,并最终以WSGI的方式将status、headers、response body返回给WSGI Server
  5. 最后,WSGI Server再将WSGI格式的数据转换为HTTP格式的数据返回给客户端

可见:WSGI Server主要进行请求数据的格式转换 HTTP <–> WSGI, 然后Flask 作为WSGI app 以WSGI的方式被调用、执行、返回。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值