Nginx多服务场景下,如何为内部XHR请求实现干净URL?
无需硬编码前缀解决Mojolicious应用反向代理路由问题
方案1:通过Mojolicious配置基础路径(静态指定前缀)
在应用中设置基础路径,让所有生成的URL自动带上前缀,无需硬编码。
代码实现
在应用启动脚本中添加配置和钩子:
use Mojolicious::Lite; # 可通过环境变量灵活切换前缀(App B部署时设为/B) my $base_path = $ENV{MOJO_BASE_PATH} || '/A'; # 设置请求的base路径,url_for会自动使用该前缀生成URL app->hook(before_dispatch => sub { my $c = shift; $c->req->url->base->path($base_path); }); # 示例路由 get '/' => sub { my $c = shift; $c->render(template => 'index'); }; app->start;
模板中正常使用url_for生成路径即可,无需手动加前缀:
<!-- 静态资源 --> <link rel="stylesheet" href="<%= url_for('css/my.css') %>"> <!-- XHR请求 --> <script> fetch('<%= url_for('/api/submit') %>', { method: 'POST' }) .then(res => res.json()) .then(data => console.log(data)); </script>
部署时只需调整MOJO_BASE_PATH环境变量,应用代码无需修改,保持可移植性。
方案2:通过Nginx传递前缀头,应用动态适配(推荐,最灵活)
让Nginx在代理请求时传递前缀信息,应用自动读取并设置base路径,完全无需提前指定前缀,适配任意部署路径。
Nginx配置调整
location ~ ^/A(.*)$ { proxy_pass http://127.0.0.1:3000$1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; # 传递当前路由前缀给应用 proxy_set_header X-Forwarded-Prefix /A; } location ~ ^/B(.*)$ { proxy_pass http://127.0.0.1:3001$1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Prefix /B; }
应用代码适配
在Mojolicious中添加钩子,读取Nginx传递的头信息并设置base路径:
app->hook(before_dispatch => sub { my $c = shift; # 读取Nginx传递的前缀头 if (my $prefix = $c->req->headers->header('X-Forwarded-Prefix')) { $c->req->url->base->path($prefix); } });
之后模板和路由中依然正常使用url_for,生成的URL会自动带上对应的前缀,回传Nginx时能正确路由到对应应用。
方案3:Nginx响应内容替换(临时应急方案)
如果不想修改应用代码,可以用Nginx的sub_filter模块替换响应中的相对路径,给所有URL加上前缀。但此方法仅适用于静态文本中的路径,动态生成的URL可能无法覆盖,不推荐长期使用。
Nginx配置示例
location ~ ^/A(.*)$ { proxy_pass http://127.0.0.1:3000$1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; # 替换响应中的相对路径前缀 sub_filter 'href="/' 'href="/A/'; sub_filter 'src="/' 'src="/A/'; sub_filter 'action="/' 'action="/A/'; sub_filter 'fetch("/' 'fetch("/A/'; sub_filter_once off; # 替换所有匹配项 }
内容的提问来源于stack exchange,提问作者bliako
相关产品推荐
相关产品推荐

