Django @login_required 使用 nginx 和 fastcgi 时导致重定向循环
Posted
技术标签:
【中文标题】Django @login_required 使用 nginx 和 fastcgi 时导致重定向循环【英文标题】:Django @login_required cause redirects loop when using nginx and fastcgi 【发布时间】:2013-02-14 11:56:13 【问题描述】:我在 settings.py 中这样设置 LOGIN_URL:
LOGIN_URL = '/login/'
在 urls.py 我和这个 URLConf:
(r'^$', 'agent.index.redirect'), (r'^login/$', 'django.contrib.auth.views.login', 'template_name':'login.html'),
agent.index.redirect 视图是这样的:
@login_required def redirect(request): ...
我像这样运行我的 Django 网站:
python manage.py runfcgi host=127.0.0.1 port=8090 --settings=settings
nginx.conf 是这样的:
user nobody nobody; worker_processes 5; #error_log /var/log/nginx/error_log info; events worker_connections 1024; use epoll; http include mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] ' '"$request" $status $bytes_sent ' '"$http_referer" "$http_user_agent" ' '"$gzip_ratio"'; client_header_timeout 10m; client_body_timeout 10m; send_timeout 10m; connection_pool_size 256; client_header_buffer_size 1k; large_client_header_buffers 4 2k; request_pool_size 4k; gzip on; gzip_min_length 1100; gzip_buffers 4 8k; gzip_types text/plain; output_buffers 1 32k; postpone_output 1460; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 75 20; ignore_invalid_headers on; index index.html; server listen 80; server_name localhost; root /web/agent; location /static alias /web/agent/media; access_log off; expires 30d; location /media alias /web/agent/admin_media; access_log off; expires 30d; location / # host and port to fastcgi server fastcgi_pass 127.0.0.1:8090; fastcgi_param PATH_INFO $fastcgi_script_name; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param QUERY_STRING $query_string; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_pass_header Authorization; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_connect_timeout 30s; fastcgi_send_timeout 30s; fastcgi_read_timeout 30s; fastcgi_buffer_size 128k; fastcgi_buffers 8 128k;#8 128 fastcgi_busy_buffers_size 256k; fastcgi_temp_file_write_size 256k; fastcgi_intercept_errors on; #access_log /usr/local/nginx/logs/access_log main; #error_log /usr/local/nginx/logs/error_log;
当我访问 [http://localhost] 时,会有一个重定向循环。而nginx的access.log是这样的:
127.0.0.1 - - [28/Feb/2013:18:13:51 +0800] "GET / HTTP/1.1" 302 5 "-" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20130220 Firefox/17.0" 127.0.0.1 - - [28/Feb/2013:18:13:51 +0800] "GET /login/?next=// HTTP/1.1" 302 5 "-" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20130220 Firefox/17.0" 127.0.0.1 - - [28/Feb/2013:18:13:51 +0800] "GET /login/?next=/login//%3Fnext%3D// HTTP/1.1" 302 5 "-" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20130220 Firefox/17.0" 127.0.0.1 - - [28/Feb/2013:18:13:51 +0800] "GET /login/?next=/login//%3Fnext%3D/login//%253Fnext%253D// HTTP/1.1" 302 5 "-" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20130220 Firefox/17.0" 127.0.0.1 - - [28/Feb/2013:18:13:51 +0800] "GET /login/?next=/login//%3Fnext%3D/login//%253Fnext%253D/login//%25253Fnext%25253D// HTTP/1.1" 302 5 "-" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20130220 Firefox/17.0" ...and so on.
谁能帮忙解决这个问题?
【问题讨论】:
你的问题让我想起了this question。尝试删除fastcgi_param SCRIPT_NAME $fastcgi_script_name;
。
@Alasdair 它有效。非常感谢!但我不知道为什么。
我很高兴它成功了 :)
【参考方案1】:
啊哈,原因是:
Django 使用 PATH_INFO 来匹配 urlpatterns。 Nginx 的 fastcgi_params include 没有设置。它确实设置了 SCRIPT_NAME。如果 PATH_INFO 和 SCRIPT_NAME 都设置为 $fastcgi_script_name,Django 似乎会为所有请求获取一个空路径。只需设置 PATH_INFO!
在http://aftnn.org/2009/jan/23/nginx-django-fastcgi/ 上查看更多信息。
所以解决方案只是删除这一行:fastcgi_param SCRIPT_NAME $fastcgi_script_name;
非常感谢@Alasdair。
【讨论】:
【参考方案2】:这通常表明您有另一个与请求的 URL(可能是所有 url)匹配并重定向到登录页面的 URL 模式。例如:
(r'^', 'agent.index.redirect'),
^ left out the end-of-string $
这会导致您遇到的重定向循环。除了问题中列出的以外,您还有其他 url 格式吗?
【讨论】:
只有在我使用nginx和fastcgi时才会出现这个问题。如果使用python manage.py runserver
运行站点,则没有重定向循环。以上是关于Django @login_required 使用 nginx 和 fastcgi 时导致重定向循环的主要内容,如果未能解决你的问题,请参考以下文章
Django @login_required 删除 https
使用Django自带的登录访问限制login_required
为啥Django在使用@login_required装饰器时有太多的登录重定向?