Apache 反向代理时如何正确处理相对 URL?
子路径反代需检查应用生成的 URL 与 base path,映射不对称并非必然破坏普通相对链接;用 ProxyPassReverse 修正重定向头、HTML 内容里的链接用 mod_proxy_html 或 mod_substitute 改写。本文给完整配置。
问题根源:反代到子路径时,根相对链接、绝对链接、base 标签和重定向可能"出界";普通相对链接不必然因映射不对称而失效。处理三件套:①ProxyPass 与 ProxyPassReverse 配对使用(后者修正后端返回的 Location 头);②页面内容里的绝对/相对链接用 mod_proxy_html 或 mod_substitute 改写;③最省心的根本解:让后端应用知道自己挂在子路径下**(应用层配置 base path)。**
基础配置
<VirtualHost *:80>
ServerName example.com
ProxyPass /app1/ http://internal:8080/app1/
ProxyPassReverse /app1/ http://internal:8080/app1/
</VirtualHost>
ProxyPassReverse 把后端响应头里的 Location: http://internal:8080/app1/login 改写为客户端可访问的代理地址(常见为 http://example.com/app1/login,不保证总是路径形式)——302 跳转不错乱。
启用模块:
sudo a2enmod proxy proxy_http proxy_html substitute
sudo systemctl restart apache2
两端路径与应用 URL 要匹配
# 合法的非对称映射:需检查应用生成的 URL/base/cookie,并非相对链接全断
ProxyPass /app1/ http://internal:8080/
# ✅ 对称:后端也挂在 /app1/ 下
ProxyPass /app1/ http://internal:8080/app1/
后端不能配置 base path 时,可评估内容改写或使用独立子域名;改写不能保证覆盖脚本动态生成的 URL:
ProxyPass /app1/ http://internal:8080/
ProxyPassReverse /app1/ http://internal:8080/
# 改写 HTML 里的链接
ProxyHTMLEnable On
ProxyHTMLURLMap http://internal:8080/ /app1/
也可按实际 HTML 使用 mod_substitute 做经过测试的有限替换,但不要泛改所有 href="/ 或 src="/:协议相对 URL、已带前缀地址、压缩内容和动态脚本都可能误伤。
检查清单
- 页面 302 跳转后地址栏对不对(ProxyPassReverse 管)
- 页面里 CSS/JS 404(相对路径出界,看浏览器 Network 的实际请求路径)
- Cookie 的 Path 属性(
ProxyPassReverseCookiePath / /app1/) - 在访问日志中核对实际请求路径和 404。日志集中到观测云时,按 Pipeline 规则提取路径、状态码后筛选,再与浏览器 Network 对照确认是否为改写遗漏。
常见问题(FAQ)
Q:ProxyPass 末尾的斜杠到底要不要?
A:两端要保持一致(都带或都不带),不一致会导致路径拼接错位——这是 Apache 反代最经典的坑。
Q:后端是 HTTPS 怎么办?
A:ProxyPass /app1/ https://internal:8443/app1/,并启用 mod_ssl、mod_proxy/mod_proxy_http,并配置 SSLProxyEngine On 及回源证书验证;没有名为 ssl_proxy 的模块。
Q:WebSocket 应用还要配什么?
A:按版本配置:Apache 2.4.47+ 的 mod_proxy_http 可处理协议升级;较旧组合可使用 mod_proxy_wstunnel,并核对实际 Upgrade 路径。