Nginx. 如何根据 uri 选择位置和/或上游?

Nginx. 如何根据 uri 选择位置和/或上游?

问题。我有一个或多个域名,它们为一些 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";
}

相关内容