Django + uWSGI + nginx URL映射

7
我希望在NGINX后面使用uWSGI运行Django。
我将使用Django作为API服务,它应该存在于这个链接中: project.test/api Django项目本身是空白的(1.9.6),只创建了一个app,迁移并创建了一个超级用户。
我的项目结构如下:
/vagrant/api/here-lives-whole-django
/vagrant/api/uwsgi_params
/vagrant/frontend/some-frontend-work-seperated-from-django
我的NGINX设置如下:
upstream testing {
    server 127.0.0.1:8000;
}

server {
    listen   80;

    server_name www.testing.test;

    charset  utf-8;

    client_max_body_size  75M;

    access_log  /var/log/nginx/www.testing.test.access.log;
    error_log  /var/log/nginx/www.testing.test.error.log;

    location /api/ {
        include /vagrant/api/uwsgi_params;
        uwsgi_pass testing;
    }

    location / {
        root /vagrant/frontend;
    }
}

uwsgi_params 文件:

uwsgi_param  QUERY_STRING       $query_string;
uwsgi_param  REQUEST_METHOD     $request_method;
uwsgi_param  CONTENT_TYPE       $content_type;
uwsgi_param  CONTENT_LENGTH     $content_length;

uwsgi_param  REQUEST_URI        $request_uri;
uwsgi_param  PATH_INFO          $document_uri;
uwsgi_param  DOCUMENT_ROOT      $document_root;
uwsgi_param  SERVER_PROTOCOL    $server_protocol;
uwsgi_param  REQUEST_SCHEME     $scheme;
uwsgi_param  HTTPS              $https if_not_empty;

uwsgi_param  REMOTE_ADDR        $remote_addr;
uwsgi_param  REMOTE_PORT        $remote_port;
uwsgi_param  SERVER_PORT        $server_port;
uwsgi_param  SERVER_NAME        $server_name;

我的Django URL模式:
urlpatterns = [
    url(r'^admin/', admin.site.urls),
]

目前我正在使用以下命令运行Django:
uwsgi --socket :8000 --wsgi-file wsgi.py

我能够访问Django,但当我尝试访问
www.testing.test/api/admin
时,我收到了一个404错误(来自Django的调试信息)。

Page not found (404)
Request Method: GET
Request URL:    http://www.testing.test/api/admin
Using the URLconf defined in testing.urls, Django tried these URL patterns, in this order:
^admin/
The current URL, api/admin, didn't match any of these.

我知道对于那些习惯这种东西的人来说,这将是非常简单的事情,请原谅我因为我是新手。

附注:我找到了一些类似的问题,其中一些人已经处理过了。

uwsgi_param SCRIPT_NAME /api;
uwsgi_modifier1 30; 

但这只是让我的Django告诉我一个404错误,其中包括
Request URL:    http://www.testing.test/api/api/admin

当我发出请求时

Request URL:    http://www.testing.test/api/admin
1个回答

8
我有些难以理解你的问题,但基本上可以概括为:我希望 nginx 将所有对 /api/ 的调用都转发给 django,但 django 收到的 URL 带有前缀 /api/

nginx 技巧(不适用于内部 URL)

我建议使用 nginx 的 rewrite 来解决这个问题。

location /api/ {
    rewrite ^/api/(.*) /$1  break;
    include /vagrant/api/uwsgi_params;
    uwsgi_pass testing;
}

它将删除URL的/api/部分,并保留块以uwsgi_pass进入Django。

Django解决方案(在我看来有点不太好)

以上适用于第一个进入Django的URL。然而,Django对已删除的前缀一无所知,将难以生成指向自身的URL。这在一些简单的API中可能不是问题,但更常见的情况是会出现问题。

我想,唯一可行的方法是将前缀添加到基本URLconf中。

from django.conf.urls import include

mypatterns = [
    url(r'^admin/', admin.site.urls),
]

urlpatterns = [
    url(r'^api/', include(mypatterns)),
]

虽然我认为这是一个非常不优雅的解决方案。


我尝试在链接 domain.test/api/* 上运行 Django,因此应该可以通过 domain.test/api/admin 访问 Django 内置的管理界面。如果我按照您描述的更改我的项目并尝试转到 domain.test/api/admin,则会被重定向到 domain.test/admin。 - user6354141
您不会因为 break 而被抛出,它确保了 rewrite 不会被扔回 URL 匹配过程中。然而,Django 自动生成 URL 时存在问题(我更新了答案以反映这一点)。我想,在基本 URL 配置中将 /api/ 前缀添加给所有 URL 是一个不太优雅但可行的解决方案。 - grochmal
它确实这样做,或者看起来像是这样做。 当我输入 domain.test/api/admin 时,它会变成 domain.test/admin。 顺便说一下,我相信我搞砸了一些东西,因为我没有完全按照你以前的答案去做,因为你删除了它们。 你还记得你写了什么吗?可以帮助我恢复我的虚拟机上的一些配置。 - user6354141
我在胡言乱语关于随机的uWSGI配置,因为我误读了你的问题。这完全是我的错。然而,对于一个好的uwsgi配置的例子,我总是回到这个人的gist帖子 - grochmal
2
在设置了 rewrite ^/api/(.*) /$1 break; 后,我还需要添加 uwsgi_param SCRIPT_NAME /api; 才能让 Django 正确路由。我一整天都被这个问题困扰着,这真的帮了我很大的忙! - Ashley 'CptLemming' Wilson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接