Nginx 位置语句在正则表达式和正常匹配中的行为不同

Nginx location statement behaves differently in regex and normal matching

我在这两种情况下看到了不同的行为:

location ~ /(?<version>v[12]) {
    proxy_pass https://localhost/api/$version;
}

location /v2 {
    proxy_pass https://localhost/api/v2;
}

如果我请求 /v2/login,我会在正则表达式配置中看到对 /v2 的请求,而直接匹配会正确保留整个请求 url.

我尝试添加第二个捕获组,/(?<version>v[12])/(?<path>.*),然后它基本上起作用了。但是,它似乎与 PUT/POST 混为一谈。

我是否缺少一些解释?我阅读了 documentation,但据我所知,使用或不使用正则表达式应该没有任何区别。

不幸的是,官方文档缺少许多重要说明。如果您发现 Nginx 有一些文档无法解释的异常情况,那么我建议您查看 wiki。在你的情况下,有趣的部分是:

A special case is using variables in the proxy_pass statement: The requested URL is not used and you are fully responsible to construct the target URL yourself.

因此,一旦您在 proxy_pass 指令中引入 $version,Nginx 便开始忽略原始请求 URI,仅发送 proxy_pass URI 部分中的内容。

这就是为什么如果你只需要涵盖两种情况(v1v2),我强烈建议不要乱用正则表达式,而是像你一样定义两个公共前缀位置在你的第二个例子中做了。 Nginx配置不是编程代码,重复部分配置就可以了。

但是,如果出于某种原因您确实必须使用正则表达式位置,则您将不得不重写您的 URI:

location ~ /(?<version>v[12]) {
    rewrite ^/(.*)$ /api/ break;
    proxy_pass https://localhost;
}

或者自己构造完整的URI:

location ~ /(?<version>v[12])(?<rest>.*)$ {
    proxy_pass https://localhost/api/$version$rest$is_args$args;
}