美文网首页
通过源码看 Flask redirect 返回响应时为响应头的L

通过源码看 Flask redirect 返回响应时为响应头的L

作者: u14e | 来源:发表于2018-05-19 16:33 被阅读164次

    背景


    使用redirect,让用户登录之后重定向到首页

    @bp.route('/login', methods=['GET', 'POST'])
    def login():
        ......
        return redirect('/')
        ......
    

    源码执行过程中的关键代码


    1. 首先执行redirect函数,为响应头添加Location属性,并返回响应对象response
    def redirect(location, code=302, Response=None):
        ......
        response.headers['Location'] = location  # '/'
        return response
    
    1. 路由函数返回响应对象responseBaseResponse对象被当作函数调用,并调用__call__方法:
    class BaseResponse(object):
        ......
            def __call__(self, environ, start_response):
                app_iter, status, headers = self.get_wsgi_response(environ)
                start_response(status, headers)
                return app_iter
    
    1. __call__方法调用get_wsgi_response实例方法,处理相关的响应,这里的environ是接收到的请求的一系列数据,包括后面要用到的协议(wsgi.url_scheme):
    class BaseResponse(object):
        def get_wsgi_response(self, environ):
            headers = self.get_wsgi_headers(environ)
            app_iter = self.get_app_iter(environ)
            return app_iter, self.status, headers.to_wsgi_list()
    
    1. get_wsgi_headers方法,处理响应头部信息,调用get_current_url获取当前的绝对路径
    class BaseResponse(object):
        def get_wsgi_headers(self, environ):
            headers = Headers(self.headers)
            location = None
    
            for key, value in headers:
                ikey = key.lower()
                if ikey == u'location':
                    location = value  # 首页的话,就是'/'
    
            if location is not None:
                old_location = location
                if self.autocorrect_location_header:  # 默认为True
                    current_url = get_current_url(environ, root_only=True)  # 得到`http://localhost:3000/`
                    location = url_join(current_url, location) # 连接后就是`http://localhost:3000/`
                if location != old_location:
                    headers['Location'] = location
    
            return headers
    
    1. get_current_url函数根据environ['wsgi.url_scheme']获取协议,并返回根路径的绝对路径:
    def get_current_url(environ, root_only=False, strip_querystring=False,
                        host_only=False, trusted_hosts=None):
        tmp = [environ['wsgi.url_scheme'], '://', get_host(environ, trusted_hosts)]
        # ['http', '://', 'localhost:3000', '', '/']
        ......
        return uri_to_iri(''.join(tmp)) # 'http://localhost:3000/'
    
    1. 最后BaseResponse返回给wsgi_app返回给wsgi接口:
    class Flask(_PackageBoundObject):
        def wsgi_app(self, environ, start_response):
            return response(environ, start_response)
            
        def __call__(self, environ, start_response):
            return self.wsgi_app(environ, start_response)
    

    结论


    所以此时浏览器接收到的响应头部里面的Locationhttp://localhost:3000/,如果使用Nginx反向代理https到本机的http的话,记得设置反向代理头部的协议proxy_set_header X-Forwarded-Proto $scheme;

    不然redirect的时候,environ['wsgi.url_scheme']获得的是http,会重定向到http://localhost:3000/,而不是https://localhost:3000/

    相关文章

      网友评论

          本文标题:通过源码看 Flask redirect 返回响应时为响应头的L

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