You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 14:03:21