在 https 反向代理后的 IIS 站点,配置 IIS 重定向会导致 https 变为 http,如何让 IIS 重定向返回相对地址的 Location 头
问题
在 IIS 中配置 HTTP 重定向,destination 明明写的是相对路径:
<system.webServer>
<httpRedirect enabled="true" exactDestination="true" httpResponseStatus="Found" destination="/test/login/#/sso$Q" />
</system.webServer>
但实际返回的 Location 响应头还是从 http:// 开始的完整地址:
Location: http://主机名/test/login/#/sso?ticket=abc123
在反向代理、内外网映射等场景下,这可能会导致 https 地址被降级为 http,进而导致地址不能访问或者还需要多一次重定向。
原因
IIS 的 HTTP 重定向模块(httpRedirect)在生成 302 响应时,会自动用当前请求的协议和 Host 头把目标补全成绝对地址,没有任何开关可以关掉。exactDestination 只控制是否把原请求路径追加到目标后面,与绝对/相对无关。
URL Rewrite 模块的入站 Redirect 动作也是同样的行为,即使 url 写相对路径,最终也会自动补全主机名(微软确认的设计行为)。
解决方案
用 URL Rewrite 的出站规则(outboundRules)改写 RESPONSE_Location。出站规则是在响应发出前对响应头做纯文本正则替换,不走 URL 补全逻辑,所以可以把协议和主机名剥掉,# 和查询串都能原样保留:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<httpRedirect enabled="true" exactDestination="true" httpResponseStatus="Found" destination="/test/login/#/sso$Q" />
<rewrite>
<outboundRules>
<rule name="LocationToRelative">
<match serverVariable="RESPONSE_Location" pattern="^https?://[^/]+(/.*)" />
<action type="Rewrite" value="{R:1}" />
</rule>
</outboundRules>
</rewrite>
</system.webServer>
</configuration>
实测效果(curl -I http://localhost:8099/some/old/path?ticket=abc123):
# 加规则前
Location: http://localhost:8099/test/login/#/sso?ticket=abc123
# 加规则后
Location: /test/login/#/sso?ticket=abc123
注意:完整版 IIS 默认不带 URL Rewrite 模块,需要单独安装:https://www.iis.net/downloads/microsoft/url-rewrite (IIS Express 自带)。
这个出站规则对任何来源的重定向响应都生效(包括后端应用自己发出的 302),所以它也是反向代理场景下修正 Location 头的通用做法。
参考:
输了你,赢了世界又如何...

浙公网安备 33010602011771号