问题描述
我有一个 Django 项目,其中包含一个名为“Surveys”的应用程序 - 希望可以通过 http://example.com/Surveys/ViewInspection/1 访问诸如 http://example.com/Inspections/ViewInspection/1 之类的 URL。
使用 Apache 2.4 和 mod_rewrite,我制定了以下规则集以允许这样做:
RewriteEngine On
RewriteRule ^/inspections(.+)$ /Surveys$1 [PT]
并且一切似乎都运行良好,除非未经身份验证的用户尝试访问上述 URL(具有 @login_required 装饰器的视图。
/Auth/Login?next=/Ins/Surveys/Viewinspection/1
经过一番挖掘,"/Ins/Surveys/Viewinspection/1" 是 request.path 的值,而 request.path_info 正确设置为 /Surveys/Viewinspection/1 - Auth 代码采用 .path 和弄错了。如果我使用比“inspections”更短的字符串,则 Ins 部分会减少直到消失,然后一切正常。
mod_rewrite 日志在这种情况下看起来是正确的:
[Tue Feb 23 23:52:49.617840 2021] [rewrite:trace2] [pid 2760:tid 140156097316608] mod_rewrite.c(483): [client 213.18.147.204:4054] 213.18.147.204 - - [hostname/sid#7f78a4651338][rid#7f78a53910a0/initial] init rewrite engine with requested uri /inspections/Viewinspection/2
[Tue Feb 23 23:52:49.617906 2021] [rewrite:trace3] [pid 2760:tid 140156097316608] mod_rewrite.c(483): [client 213.18.147.204:4054] 213.18.147.204 - - [hostname/sid#7f78a4651338][rid#7f78a53910a0/initial] applying pattern '^/inspections(.+)$' to uri '/inspections/Viewinspection/2'
[Tue Feb 23 23:52:49.617940 2021] [rewrite:trace2] [pid 2760:tid 140156097316608] mod_rewrite.c(483): [client 213.18.147.204:4054] 213.18.147.204 - - [hostname/sid#7f78a4651338][rid#7f78a53910a0/initial] rewrite '/inspections/Viewinspection/2' -> '/Surveys/Viewinspection/2'
[Tue Feb 23 23:52:49.617956 2021] [rewrite:trace2] [pid 2760:tid 140156097316608] mod_rewrite.c(483): [client 213.18.147.204:4054] 213.18.147.204 - - [hostname/sid#7f78a4651338][rid#7f78a53910a0/initial] forcing '/Surveys/Viewinspection/2' to get passed through to next API URI-to-filename handler
[Tue Feb 23 23:52:49.618103 2021] [rewrite:trace2] [pid 2760:tid 140156097316608] mod_rewrite.c(483): [client 213.18.147.204:4054] 213.18.147.204 - - [hostname/sid#7f78a4651338][rid#7f78a54060a0/subreq] init rewrite engine with requested uri /Surveys/Viewinspection/2
[Tue Feb 23 23:52:49.618119 2021] [rewrite:trace3] [pid 2760:tid 140156097316608] mod_rewrite.c(483): [client 213.18.147.204:4054] 213.18.147.204 - - [hostname/sid#7f78a4651338][rid#7f78a54060a0/subreq] applying pattern '^/inspections(.+)$' to uri '/Surveys/Viewinspection/2'
[Tue Feb 23 23:52:49.618131 2021] [rewrite:trace1] [pid 2760:tid 140156097316608] mod_rewrite.c(483): [client 213.18.147.204:4054] 213.18.147.204 - - [hostname/sid#7f78a4651338][rid#7f78a54060a0/subreq] pass through /Surveys/Viewinspection/2
知道我在这里做错了什么导致 request.path 出错并在登录后弄乱重定向吗?
如果我缩短重写规则中的“检查”部分,它会相应地缩短不正确的 request.path 的“Ins”部分 - 因此适当的短(
解决方法
在添加 WSGI 中间件以将 WSGI 信息删除到 Apache 错误日志后,我在 django.core.handlers.wsgi.py 中找到了罪魁祸首第 177 行
if script_url:
if b'//' in script_url:
# mod_wsgi squashes multiple successive slashes in PATH_INFO,# do the same with script_url before manipulating paths (#17133).
script_url = _slashes_re.sub(b'/',script_url)
path_info = get_bytes_from_wsgi(environ,'PATH_INFO','')
script_name = script_url[:-len(path_info)] if path_info else script_url
else:
script_name = get_bytes_from_wsgi(environ,'SCRIPT_NAME','')
在这里,我们进入这个小代码块,因为 script_name 是来自 mod_wsgi 的零字符串(我不在子目录中)。 path_info
被 Apache 设置为 /Surveys/ViewInspection/1
(正确,来自 mod_rewrite); script_url
是 /Inspections/ViewInspection/1
(再次正确 - 修改前的 URL)。
代码 script_url[:-len(path_info)]
盲目地去掉了 path_info 上的长度作为脚本名称,结果弄错了。
这里的解决方法是添加:
FORCE_SCRIPT_NAME = ""
到 Django settings.py 文件。