背景
使用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/
。