Apache 反向代理时如何正确处理相对 URL?
相对 URL 问题的根源是路径前缀与后端不一致:保持 ProxyPass 两端路径一致、用 ProxyPassReverse 修正重定向头、HTML 内容里的链接用 mod_proxy_html 或 mod_substitute 改写。本文给完整配置。
问题根源:反代路径(如 /app1/)与后端真实路径不一致时,页面里的相对链接和重定向会"出界"。处理三件套:①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 改写成 /app1/login——302 跳转不错乱。
启用模块:
sudo a2enmod proxy proxy_http proxy_html substitute
sudo systemctl restart apache2
两端路径要对称(最高频坑)
# ❌ 路径不对称:后端根路径内容暴露到 /app1/,相对链接全断
ProxyPass /app1/ http://internal:8080/
# ✅ 对称:后端也挂在 /app1/ 下
ProxyPass /app1/ http://internal:8080/app1/
如果后端不能改路径(第三方应用),只能内容改写:
ProxyPass /app1/ http://internal:8080/
ProxyPassReverse /app1/ http://internal:8080/
# 改写 HTML 里的链接
ProxyHTMLEnable On
ProxyHTMLURLMap http://internal:8080/ /app1/
或用 mod_substitute:
<Location /app1/>
ProxyPass http://internal:8080/
ProxyPassReverse http://internal:8080/
AddOutputFilterByType SUBSTITUTE text/html
Substitute "s|href=\"/|href=\"/app1/|i"
Substitute "s|src=\"/|src=\"/app1/|i"
</Location>
检查清单
- 页面 302 跳转后地址栏对不对(ProxyPassReverse 管)
- 页面里 CSS/JS 404(相对路径出界,看浏览器 Network 的实际请求路径)
- Cookie 的 Path 属性(
ProxyPassReverseCookiePath / /app1/)
观测云对照
出界的请求在日志里现形。 相对路径错乱会产生一批打向错误路径的 404;Nginx/Apache 日志采集到观测云后按路径聚合,404 集中的错误路径正是改写遗漏处。
常见问题(FAQ)
Q:ProxyPass 末尾的斜杠到底要不要?
A:两端要保持一致(都带或都不带),不一致会导致路径拼接错位——这是 Apache 反代最经典的坑。
Q:后端是 HTTPS 怎么办?
A:ProxyPass /app1/ https://internal:8443/app1/,并启用 ssl_proxy 模块(a2enmod ssl proxy)。
Q:WebSocket 应用还要配什么?
A:单独为 ws 路径配 RewriteRule + proxy_wstunnel 模块转发 Upgrade 请求。