在 Nginx 中的位置下为多个代理端点提供服务

ham*_*tar 14 nginx reverse-proxy

我有几个 API 端点,我想从一个位置下/api提供服务,子路径指向不同的端点。具体来说,我希望 webdis/api可以在/api/mypath.

我不担心与 webdis API 发生冲突,因为我使用的子路径不太可能与 redis 命令名称发生冲突,并且还可以完全控制 API 的设计以避免冲突。

这是我一直在攻击的测试服务器的配置文件:

server {
  listen 80;
  server_name localhost;
  server_name 192.168.3.90;
  server_name 127.0.0.1;

  location / {
    root /home/me/src/phoenix/ui;
    index index.html;
  }

  # temporary hardcoded workaround
  location = /api/mypath/about {
    proxy_pass http://localhost:3936/v1/about;
  }

  location /api {
    rewrite ^/api/(.*)$ /$1 break;
    proxy_pass http://localhost:7379/;
  }

  # tried this but it gives "not found" error
  #location ^~ /api/mypath/ {
  #  rewrite ^/api/mypath/(.*)$ /$1 break;
  #  proxy_pass http://localhost:3936/v1/;
  #}
  #
  #location ^~ /api {
  #  rewrite ^/api/(.*)$ /$1 break;
  #  proxy_pass http://localhost:7379/;
  #}
}
Run Code Online (Sandbox Code Playgroud)

如何更改我的解决方法,以便任何请求都/api/mypath/*将发送到端口 3936 的端点,而其他所有请求都将发送到端口 7379?

Ale*_*Ten 28

你不需要为此重写。

server {
  ...

  location ^~ /api/ {
    proxy_pass http://localhost:7379/;
  }
  location ^~ /api/mypath/ {
    proxy_pass http://localhost:3936/v1/;
  }
}
Run Code Online (Sandbox Code Playgroud)

根据nginx文档

位置可以由前缀字符串或正则表达式定义。正则表达式由前面的~*修饰符(对于不区分大小写的匹配)或~修饰符(对于区分大小写的匹配)指定。为了找到与给定请求匹配的位置,nginx 首先检查使用前缀字符串(前缀位置)定义的位置。其中,选择并记住匹配前缀最长的位置。然后按照它们在配置文件中出现的顺序检查正则表达式。正则表达式的搜索在第一次匹配时终止,并使用相应的配置。如果找不到与正则表达式的匹配项,则使用之前记住的前缀位置的配置。

如果最长匹配前缀位置具有^~修饰符,则不检查正则表达式。

因此,任何以 开头的请求/api/mypath/将始终由第二个块提供服务,因为这是最长的匹配前缀位置。

任何以/api/not开头的请求mypath/总是由第一个块提供服务,因为第二个块不匹配,因此使第一个块成为最长匹配前缀位置。

  • 如果您查看位置修饰符(`=`、`~*`、`~` 和`^~`),`^~` 不包括正则表达式(因为`~` 表示正则表达式)可能看起来违反直觉匹配)...但是,如果您还记得,正则表达式字符类中的`^`(例如`[^az]`)*否定*该类(因此示例意味着(任何字符*除了*来自az的字符);类似地,`^~` 否定任何潜在的正则表达式位置块。 (2认同)

ham*_*tar 11

好吧想通了,我认为“未找到”错误来自 nginx,但实际上它来自我的 API。如果有人感兴趣,这是我的解决方案:

server {
  listen 80;
  server_name localhost;
  server_name 192.168.3.90;
  server_name 127.0.0.1;

  location / {
    root /home/me/src/phoenix/ui;
    index index.html;
  }

  # automatically go to v1 of the (grape) API
  location ^~ /api/mypath/ {
    rewrite ^/api/mypath/(.*)$ /v1/$1 break;
    proxy_pass http://localhost:3936/;
  }

  location ^~ /api {
    rewrite ^/api/(.*)$ /$1 break;
    proxy_pass http://localhost:7379/;
  }
}
Run Code Online (Sandbox Code Playgroud)