![Nginx. 如何根据 uri 选择位置和/或上游?](https://linux22.com/image/781249/Nginx.%20%E5%A6%82%E4%BD%95%E6%A0%B9%E6%8D%AE%20uri%20%E9%80%89%E6%8B%A9%E4%BD%8D%E7%BD%AE%E5%92%8C%2F%E6%88%96%E4%B8%8A%E6%B8%B8%EF%BC%9F.png)
问题。我有一个或多个域名,它们为一些 uri 提供默认上游(CMS),还有一些 uri 需要不同的上游(但仍然太多而无法轻松列出,而且差异太大而无法用正则表达式捕获它们)。
现在,如果两个上游的所有配置都相同,除了两个上游本身之外,我认为我已经解决了这个问题够好了方式如下:
map $host$request_uri $select_upstream_with_or_without_cache {
default http://upstream_def;
~^path1$ http://upstream_special;
~^path2$ http://upstream_special;
~^path3$ http://upstream_special;
~^path4$ http://upstream_special;
# remember! Here path is, beside the $host, wildly different even within the same domain
}
[...config...]
server {
server_name server-with-same-params.for-different-upstreams.example;
[...config...]
location / {
proxy_pass $select_upstream_with_or_without_cache;
proxy_read_timeout 90s;
proxy_connect_timeout 90s;
proxy_send_timeout 90s;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_hide_header Etag;
proxy_hide_header Accept-encoding;
proxy_hide_header Via;
}
}
但是,如果我需要将不同的参数传递给不同的上游怎么办?我并没有找到一个干净的解决方案。我找到了一个使用额外重定向(30X)的解决方案,但这些对用户来说并不透明,帮手路径会显示在浏览器中,即使只显示一小段时间。有什么想法吗?
我想要实现的目标是这样的:
map $host$request_uri $select_upstream_with_or_without_cache {
default go_to_location_upstream_def;
~^path1$ go_to_location_upstream_special;
~^path2$ go_to_location_upstream_special;
~^path3$ go_to_location_upstream_special;
~^path4$ go_to_location_upstream_special;
# remember! Here path is, beside the $host, wildly different even within the same domain
}
[...config...]
server {
server_name server-with-diff-params.for-different-upstreams.example;
[...config...]
# how to have two locations, with different configs, that are selected according to the
# uris (given that the uris are very different and not really caught by regexps) ?
# how to do something like the following ?
location @upstream_def {
proxy_pass http://upstream_def;
[configuration X]
}
location @upstream_special {
proxy_pass http://upstream_special;
[configuration Y]
}
}
答案1
好的,我找到了一种方法,我相信可能还有其他方法,甚至可能更干净、更紧凑。
其要点如下:
- 在 nginx 服务器块中似乎不是可以根据 选择一个位置
uri
,从而为其选择合适的配置。 - 人们可以做的是创建内部 nginx 服务器,例如使用提供许多不同 IP 的超棒环回接口,为某个 uri 组提供所需的配置。
- 然后从主 nginx 服务器(或前端 nginx)可以使用映射根据 uri 选择后端(proxy_pass)。
- 这样,uri 的正确配置就委托给了额外的 nginx 服务器。就好像我们在前端 nginx 和后端应用程序之间添加了一层服务器,仅用于管理正确的配置。
一旦看到它,它确实是“显而易见的”,但是组合 nginx 各部分并不总是立即清楚的,但它非常有趣。
我必须清理以下内容,它可能无法直接通过复制和粘贴起作用。
upstream configA {
server 127.0.0.1:1081;
}
upstream configB {
server 127.0.0.2:1081;
}
upstream configC {
server 127.0.0.3:1081;
}
map $host $auth_basic_off_if_host {
default "dev";
nginx-testing.example.systems off;
}
map $request_uri $select_backend_based_on_path {
default http://configC;
~^/test/config/a/.* http://configA;
~^/test/config/b/.* http://configB;
}
server {
listen *:443 ssl;
server_name nginx-testing.example.systems;
ssl_certificate <path>;
ssl_certificate_key <path>;
auth_basic "dev";
auth_basic_user_file "/etc/nginx/htpasswd";
index index.html index.htm index.php;
access_log <appropriate-path-access> combined;
error_log <appropriate-path-errors>;
location /test {
proxy_pass $select_backend_based_on_path;
proxy_read_timeout 90s;
proxy_connect_timeout 90s;
proxy_send_timeout 90s;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_hide_header Etag;
proxy_hide_header Accept-encoding;
}
}
server {
listen 127.0.0.1:1081;
server_name nginx-test-config-a.example.systems;
auth_basic "$auth_basic_off_if_host";
auth_basic_user_file /etc/nginx/htpasswd;
index index.html index.htm index.php;
access_log <appropriate-path-access> combined;
error_log <appropriate-path-errors>;
location / {
proxy_pass http://app-prototype;
proxy_read_timeout 90s;
proxy_connect_timeout 90s;
proxy_send_timeout 90s;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_hide_header Etag;
proxy_hide_header Accept-encoding;
}
add_header X-test "config A" always;
}
server {
listen 127.0.0.2:1081;
server_name nginx-test-config-b.example.systems;
auth_basic "$auth_basic_off_if_host";
auth_basic_user_file /etc/nginx/htpasswd;
index index.html index.htm index.php;
access_log <appropriate-path-access> combined;
error_log <appropriate-path-errors>;
location / {
proxy_pass http://app-prototype-b;
proxy_read_timeout 90s;
proxy_connect_timeout 90s;
proxy_send_timeout 90s;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_hide_header Etag;
proxy_hide_header Accept-encoding;
}
add_header X-test "config B" always;
}
server {
listen 127.0.0.3:1081;
server_name nginx-test-config-c.example.systems;
auth_basic "$auth_basic_off_if_host";
auth_basic_user_file /etc/nginx/htpasswd;
index index.html index.htm index.php;
access_log <appropriate-path-access> combined;
error_log <appropriate-path-errors>;
location / {
index index.html index.htm index.php;
return 200 "config C";
}
add_header X-test "config C" always;
add_header Content-Type "text/plain";
}