通过源码看 Flask redirect 返回响应时为响应头的L
2018-05-19 本文已影响164人
u14e
背景
使用redirect,让用户登录之后重定向到首页
@bp.route('/login', methods=['GET', 'POST'])
def login():
......
return redirect('/')
......
源码执行过程中的关键代码
- 首先执行
redirect函数,为响应头添加Location属性,并返回响应对象response:
def redirect(location, code=302, Response=None):
......
response.headers['Location'] = location # '/'
return response
- 路由函数返回响应对象
response,BaseResponse对象被当作函数调用,并调用__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
-
__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()
-
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
-
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/'
- 最后
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)
结论
所以此时浏览器接收到的响应头部里面的Location为http://localhost:3000/,如果使用Nginx反向代理https到本机的http的话,记得设置反向代理头部的协议proxy_set_header X-Forwarded-Proto $scheme;。
不然redirect的时候,environ['wsgi.url_scheme']获得的是http,会重定向到http://localhost:3000/,而不是https://localhost:3000/。