在同一Nginx服务器块上公开多个API uri [英] Expose multiple api uri on the same nginx server block
问题描述
目标
我的目标是在同一Nginx服务器上设置暴露的多个后端api容器:
- http://localhost:80/api/account->致电http://account-service:9000/
- http://localhost:80/api/cart->致电http://cart-service:9000/
- http://localhost:80/api/order->致电http://order-service:9000/
- http://localhost:80/api/product->致电http://product-service:9000/
- ...
我的后端容器基于 php:7.2-fpm (在每个apache容器上托管的symfony),并且它们没有任何称为 api/$ {NAME_SERVICE}
(我不想在后端创建一些无用的父路由).
所以,我的要求很简单,例如,我想打电话给我时
- http://localhost:80/api/account/profile
我的后端帐户容器为这个uri服务:
- http://帐户服务:9000/profile
到目前为止我尝试过的事情
-
重写
(对fastcgi参数无济于事) - 使用
proxy_pass
设置 - 调整
fastcgi_param REQUEST_URI
(没有成功) -
别名
(禁止访问)
上游
服务器Conf
这是我的nginx.conf:
<代码> ...服务器 {server_name〜.*;client_max_body_size 50m;地点/{try_files $ uri/index.php$is_args$args;}#如果我想在http://localhost:80/上提供帐户服务,请工作#location〜^/index \ .php(/| $){#fastcgi_pass account-service:9000;#fastcgi_buffers 16 16k;#fastcgi_buffer_size 32k;#fastcgi_param SCRIPT_FILENAME/usr/src/app/public/index.php;#包括fastcgi_params;#}#我最后一次使用别名的尝试位置〜* ^/api/account {别名/;索引index.php;位置〜index \ .php(/| $){fastcgi_pass account-service:9000;fastcgi_buffers 16 16k;fastcgi_buffer_size 32k;fastcgi_param SCRIPT_FILENAME/usr/src/app/public/index.php;fastcgi_intercept_errors开启;包括fastcgi_params;}}}...
docker-compose.yml:
nginx:图片:nginx:1.15.3-alpine重新启动:失败数量:-"./build/nginx/default.conf:/etc/nginx/nginx.conf:ro";-"./logs/nginx:/var/log/nginx"端口:-"80:80";取决于:-帐户服务-帐户数据库-购物车服务-购物车数据库-订购服务-订单数据库-产品服务-产品数据库帐户服务:env_file:-config/account.env构建:应用程序/帐户服务重新启动:失败暴露:-"9000";数量:-"./apps/account-service:/usr/src/app"取决于:-帐户数据库购物车服务:...
PS: 我知道您可以将nginx conf拆分为多个服务器块,这些服务器块侦听不同的端口/主机名,但这不是我想要在这里实现的./p>
调整 fastcgi_param REQUEST_URI
是什么意思?如果您尝试为 REQUEST_URI
之前设置一些自定义值,则包括 fastcgi_params
文件,由 fastcgi_params
设置的值将覆盖您的任何调整:
fastcgi_pass服务:9000;fastcgi_param REQUEST_URI/some/path;包括fastcgi_params;#REQUEST_URI作为真实请求URI传递
但是,这将按预期工作:
fastcgi_pass服务:9000;包括fastcgi_params;fastcgi_param REQUEST_URI/some/path;#REQUEST_URI作为"/some/path"传递;
尝试使用 rewrite
更改此设置将不起作用,因为 REQUEST_URI
fastcgi参数在内部的nginx变量值设置为 $ request_uri
fastcgi_params
文件,并且该变量不会被 rewrite
指令规则更改,它是一个 $ uri
变量.
这是最有效的解决方案:
服务器{...位置〜^/api(/(?: account | cart | order | product)/.*){#删除"/api"部分从URI中搜索新的位置块最后重写^ $ 1;}位置/帐户{#删除"/帐户"部分从URI继续在当前位置块内进行处理重写^/account(.*)$ 1休息;#首先包含默认的fastcgi参数包括fastcgi_params;#我们所有的调整都在进行fastcgi_buffers 16 16k;fastcgi_buffer_size 32k;#使用重写的$ uri变量而不是默认的$ request_uri#$ uri变量不包含查询参数,因此如果存在则手动添加fastcgi_param REQUEST_URI $ uri $ is_args $ args;fastcgi_param SCRIPT_FILENAME/usr/src/app/public/index.php;fastcgi_intercept_errors开启;fastcgi_pass account-service:9000;}位置/购物车{重写^/cart(.*)$ 1休息;...fastcgi_pass cart-service:9000;}位置/顺序{重写^/order(.*)$ 1休息;...fastcgi_pass order-service:9000;}位置/产品{重写^/product(.*)$ 1休息;...fastcgi_pass产品服务:9000;}}
使用高级nginx技术可以大大优化此解决方案:
服务器{...#这是非常重要的一个!#由于我们使用变量作为后端名称,因此我们需要一个解析器来在运行时解析它#Docker默认内部解析器为127.0.0.11解析器127.0.0.11;位置〜^/api/(?api帐户|购物车|订单|产品)(?< path>/.*){包括fastcgi_params;fastcgi_buffers 16 16k;fastcgi_buffer_size 32k;#注意我们在这里使用$ path变量而不是$ uri变量fastcgi_param REQUEST_URI $ path $ is_args $ args;#假设所有后端服务中的路径均相同fastcgi_param SCRIPT_FILENAME/usr/src/app/public/index.php;fastcgi_intercept_errors开启;#使用$ api变量作为后端容器名称的一部分fastcgi_pass $ api-service:9000;}}
请注意,我们需要一个新的 resolver
指令,因为我们正在使用变量指定后端名称.您可以在此处和解析器中阅读其他详细信息来自此答案的Docker地址.>
如果您的脚本路径因不同的API后端容器而异,则可以使用其他 My goal is to setup multiple backend api container exposed on the same nginx server : My backend container are based on php:7.2-fpm (symfony hosted on every apache container) and they don't have any route called So, my request is simple, i want that when i call for example : That my backend account container serve this uri : Here is my nginx.conf : docker-compose.yml : P.S: I known that you can split nginx conf into multiple server blocks that listen on different port/hostname, but that's not what i want to achieve here. What do you mean by tweaking However this one would work as expected: Trying to change this with Here is the most simple solution that should work: This solution could be greatly optimized using advanced nginx techniques: Note that we need a new If your script path vary upon the different API backend containers, you can use an additional
这篇关于在同一Nginx服务器块上公开多个API uri的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! map $ api $ script {帐户/usr/src/app/public/index.php;购物车/some/other/path;...}服务器 {...位置〜^/api/(?api帐户|购物车|订单|产品)(?< path>/.*){...fastcgi_param SCRIPT_FILENAME $ script;...}}
Goal
api/${NAME_SERVICE}
(i don't want to create some useless parent route in my backends).
What i tried so far
rewrite
(doesn't help with fastcgi params)upstream
server with proxy_pass
fastcgi_param REQUEST_URI
(without any success)alias
(forbidden access)Conf
...
server {
server_name ~.*;
client_max_body_size 50m;
location / {
try_files $uri /index.php$is_args$args;
}
# work if i want to serve account-service on http://localhost:80/
# location ~ ^/index\.php(/|$) {
# fastcgi_pass account-service:9000;
# fastcgi_buffers 16 16k;
# fastcgi_buffer_size 32k;
# fastcgi_param SCRIPT_FILENAME /usr/src/app/public/index.php;
# include fastcgi_params;
# }
# my last attempt with alias
location ~* ^/api/account {
alias /;
index index.php;
location ~ index\.php(/|$) {
fastcgi_pass account-service:9000;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_param SCRIPT_FILENAME /usr/src/app/public/index.php;
fastcgi_intercept_errors on;
include fastcgi_params;
}
}
}
...
nginx:
image: nginx:1.15.3-alpine
restart: on-failure
volumes:
- "./build/nginx/default.conf:/etc/nginx/nginx.conf:ro"
- "./logs/nginx:/var/log/nginx"
ports:
- "80:80"
depends_on:
- account-service
- account-db
- cart-service
- cart-db
- order-service
- order-db
- product-service
- product-db
account-service:
env_file:
- config/account.env
build: apps/account-service
restart: on-failure
expose:
- "9000"
volumes:
- "./apps/account-service:/usr/src/app"
depends_on:
- account-db
cart-service:
...
fastcgi_param REQUEST_URI
? If you try to set some custom value to REQUEST_URI
before you include the fastcgi_params
file, value set by fastcgi_params
would overwrite any of your tweakings:fastcgi_pass service:9000;
fastcgi_param REQUEST_URI /some/path;
include fastcgi_params;
# REQUEST_URI passed as the real request URI
fastcgi_pass service:9000;
include fastcgi_params;
fastcgi_param REQUEST_URI /some/path;
# REQUEST_URI passed as "/some/path"
rewrite
won't work because the REQUEST_URI
fastcgi parameter is set to $request_uri
internal nginx variable value inside the fastcgi_params
file, and that variable doesn't changed by rewrite
directive rules, it is an $uri
one that does.server {
...
location ~ ^/api(/(?:account|cart|order|product)/.*) {
# strip "/api" part from the URI and search for the new location block
rewrite ^ $1 last;
}
location /account {
# strip "/account" part from the URI and continue processing within the current location block
rewrite ^/account(.*) $1 break;
# include default fastcgi parameters first
include fastcgi_params;
# all our tweakings goes after it
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
# use the rewrited $uri variable instead of the default $request_uri
# $uri variable does not include query arguments, so add them manually if they exists
fastcgi_param REQUEST_URI $uri$is_args$args;
fastcgi_param SCRIPT_FILENAME /usr/src/app/public/index.php;
fastcgi_intercept_errors on;
fastcgi_pass account-service:9000;
}
location /cart {
rewrite ^/cart(.*) $1 break;
...
fastcgi_pass cart-service:9000;
}
location /order {
rewrite ^/order(.*) $1 break;
...
fastcgi_pass order-service:9000;
}
location /product {
rewrite ^/product(.*) $1 break;
...
fastcgi_pass product-service:9000;
}
}
server {
...
# This is a very important one!
# Since we are using variables for backend name, we need a resolver to resolve it at the runtime
# Docker default internal resolver is 127.0.0.11
resolver 127.0.0.11;
location ~ ^/api/(?<api>account|cart|order|product)(?<path>/.*) {
include fastcgi_params;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
# note we are using the $path variable here instead of the $uri one
fastcgi_param REQUEST_URI $path$is_args$args;
# assuming this path is the same within all the backend services
fastcgi_param SCRIPT_FILENAME /usr/src/app/public/index.php;
fastcgi_intercept_errors on;
# using $api variable as part of backend container name
fastcgi_pass $api-service:9000;
}
}
resolver
directive since we are using a variable to specify the backend name. You can read additional details here, and the resolver address for docker taken from this answer.map
block to get the script path from the $api
variable value:map $api $script {
account /usr/src/app/public/index.php;
cart /some/other/path;
...
}
server {
...
location ~ ^/api/(?<api>account|cart|order|product)(?<path>/.*) {
...
fastcgi_param SCRIPT_FILENAME $script;
...
}
}