一、事件回顾:
早上django写好代码,和前端联调代码。
- 获取数据列表OK
- 获取数据详情301,但是仍然能获取到数据
- 修改接口后OK
- 数据修改后准备再次修改。首先,获取详情数据(301 Moved Permanently (from disk cache))渲染竟然还是之前的详情数据w(゚Д゚)w,直接从缓存获取数据,我的天哪,数据乱掉了
- 清除浏览器缓存,postman请求,没有问题啊,到底是怎么回事(⊙_⊙)?
二、思考和排查
- 为啥有301,首先看是否为服务端返回的301,一看日志,竟然看到了301,纳尼,还以为是前端的锅
- 继续排查,仔细观察url,幸亏眼神好,发现url最后没有斜杠(/),脑袋灵光一闪,难道是因为最后没有加斜杠,赶紧让前端加上
- 联调继续,发现问题完美解决
三、解剖问题
1、为啥哟?为啥加上就可以了?(⊙_⊙)? 后面的斜杠到底为啥哟?忽然想起来了django有个配置APPEND_SLASH,看来多读官方文档还是有好处的。
2、官方文档粗糙翻译:
配置名-是否追加斜杠(APPEND_SLASH):默认为True,当配置设置为True的时候,请求URL匹配不到任何URL配置中的pattern,而且其url后缀没有斜杠,一个重定向到请求url加斜杠(/)发生了。而且要注意,重定向可能会导致POST的请求数据丢失。
而且这个配置仅仅会在配置了 CommonMiddleware
这个中间件才生效。所以一定是CommonMiddleware对请求做了处理
3、代码剖析
def process_request(self, request):
# 客户端检测,立马响应不被允许的用户客户端
if 'HTTP_USER_AGENT' in request.META:
for user_agent_regex in settings.DISALLOWED_USER_AGENTS:
if user_agent_regex.search(request.META['HTTP_USER_AGENT']):
logger.warning('Forbidden (User agent): %s', request.path,
extra={
'status_code': 403,
'request': request
}
)
return http.HttpResponseForbidden('<h1>Forbidden</h1>')
# 检查是否处理斜杠(/)后缀
# and settings.PREPEND_WWW
host = request.get_host()
old_url = [host, request.path]
new_url = old_url[:]
if (settings.PREPEND_WWW and old_url[0] and
not old_url[0].startswith('www.')):
new_url[0] = 'www.' + old_url[0]
# Append a slash if APPEND_SLASH is set and the URL doesn't have a
# trailing slash and there is no pattern for the current path
if settings.APPEND_SLASH and (not old_url[1].endswith('/')):
urlconf = getattr(request, 'urlconf', None)
if (not urlresolvers.is_valid_path(request.path_info, urlconf) and
urlresolvers.is_valid_path("%s/" % request.path_info, urlconf)):
new_url[1] = new_url[1] + '/'
if settings.DEBUG and request.method == 'POST':
raise RuntimeError((""
"You called this URL via POST, but the URL doesn't end "
"in a slash and you have APPEND_SLASH set. Django can't "
"redirect to the slash URL while maintaining POST data. "
"Change your form to point to %s%s (note the trailing "
"slash), or set APPEND_SLASH=False in your Django "
"settings.") % (new_url[0], new_url[1]))
if new_url == old_url:
# No redirects required.
return
if new_url[0]:
newurl = "%s://%s%s" % (
request.scheme,
new_url[0], urlquote(new_url[1]))
else:
newurl = urlquote(new_url[1])
if request.META.get('QUERY_STRING', ''):
if six.PY3:
newurl += '?' + request.META['QUERY_STRING']
else:
# `query_string` is a bytestring. Appending it to the unicode
# string `newurl` will fail if it isn't ASCII-only. This isn't
# allowed; only broken software generates such query strings.
# Better drop the invalid query string than crash (#15152).
try:
newurl += '?' + request.META['QUERY_STRING'].decode()
except UnicodeDecodeError:
pass
// 返回401
return http.HttpResponsePermanentRedirect(newurl)
4、 在301中资源对应的路径修改为location的url,浏览器缓存301跳转后的请求结果数据
四、解决301的常用思路
1、请求加上时间戳参数,使每次请求都不一样
2、查看是否为realServer返回的301,对url处理,直接
网友评论