IIS强制HTTPS跳转:URL Rewrite 5步实战

Windows Server IIS7/8.5/10下配置HTTP强制301跳转HTTPS的完整实战:URL Rewrite模块下载安装、web.config最简模板、组合规则(强制www+移除尾斜杠)、HSTS与preload list配置、反向代理X-Forwarded-Proto处理。

更新 27 分钟阅读 2,017 阅读

大家好,我是保哥。这几年我先后帮十几位站长把Windows Server上的老站点从HTTP升级到HTTPS,几乎每一次都会被同一个问题卡住:证书装好了、443端口也通了,但访问 http://域名 依然能打开未加密版本,搜索引擎抓回的还是HTTP链接。问题的根源是IIS默认不会把旧协议跳到新协议,必须手动加一条301重定向规则。下面这篇笔记,是我在IIS7、IIS7.5、IIS8.5、IIS10四个版本上反复验证过的做法,从下载模块、写web.config、到调试踩坑都写全,方便我自己以后照抄,也希望对你有用。

为什么必须做HTTP到HTTPS的301跳转

很多人以为只要在服务器上绑定了SSL证书就大功告成,其实远远不够。我处理过的几个站点出过这些问题:

  • 百度站长平台抓取诊断显示同一篇文章既有HTTP索引又有HTTPS索引,权重被分成了两份。
  • Chrome 84之后对纯HTTP站点直接打"不安全"标签,跳出率明显升高。
  • 已经备案过HTTPS的站点如果没做强跳,混合内容(mixed content)告警会让浏览器拦截JS、CSS。
  • 微信内置浏览器对未跳转到HTTPS的页面会做拦截提示,影响转化。
  • 支付宝、微信支付的回调URL在 2021 年之后强制要求 HTTPS,纯 HTTP 站点连接入支付都做不了。
  • HTTP/2、HTTP/3、Brotli 压缩都依赖 HTTPS,没有强跳的站点享受不到这几个性能加成。

做301永久重定向可以一次解决以上问题。301状态码会让搜索引擎把旧URL的权重平滑迁移到新URL,对SEO友好;同时浏览器会缓存这条跳转,第二次访问就直接走HTTPS,不再多一次请求。这是Google与百度官方文档都推荐的做法。

301 vs 302 vs HSTS:三种"强制 HTTPS"的对比

机制是否传 SEO 权重是否减少首跳延迟是否需要浏览器配合
302 临时跳转否,每次访问都跳
301 永久跳转浏览器缓存后第二次起免跳
HSTS不直接相关是,浏览器在头部缓存有效期内自动 HTTPS是,需 max-age 内浏览器记忆
HSTS Preload List不直接相关是,首次访问就 HTTPS是,需提交到 Chromium 列表

实战里 301 + HSTS 是最佳组合:301 让所有客户端都能正确跳转、传递权重;HSTS 让回头访客省掉那一次 30x 跳转延迟。下面会把两者都讲清楚怎么配。

准备工作:URL Rewrite模块下载与安装

IIS7自带的功能里没有URL重写,必须手动安装微软出品的URL Rewrite Module。我个人比较喜欢从微软官方下载链接拿安装包,避免被第三方站点二次打包带广告。下面是我目前还在用的两个直链,注意看自己服务器是32位还是64位:

  • 32位安装包:download.microsoft.com/download/4/9/C/49CD28DB-4AA6-4A51-9437-AA001221F606/rewrite_x86_zh-CN.msi
  • 64位安装包:download.microsoft.com/download/4/E/7/4E7ECE9A-DF55-4F90-A354-B497072BDE0A/rewrite_x64_zh-CN.msi

判断系统位数最快的办法是在PowerShell里跑一句:

[Environment]::Is64BitOperatingSystem

返回True就装x64那个MSI;返回False装x86即可。安装过程是傻瓜式的,一路下一步即可。安装完之后,打开IIS管理器,选中你的站点,右侧应该多出一个"URL重写"的图标。如果没有出现,重启一下IIS管理器或者执行iisreset命令再看一次。

我有一次在Windows Server 2008 R2上安装失败,提示"安装程序无法继续"。后来发现是缺少Web Platform Installer依赖,把WebPI装上之后再装URL Rewrite就过了。如果你也碰到这种情况,先把WebPI补齐。

无人值守批量安装(多服务器场景)

如果你像我一样维护一组同型号的 Windows Server(比如某客户在三个机房各有 4 台 Web,共 12 台),用 GUI 一台一台装效率太低。MSI 安装包支持静默安装,命令是:

msiexec /i rewrite_x64_zh-CN.msi /qn /norestart /L*v rewrite_install.log

结合 PowerShell Remoting 可以一次性铺到 12 台机器:

$servers = @('web01','web02','web03','web04','web05','web06','web07','web08','web09','web10','web11','web12')
Invoke-Command -ComputerName $servers -ScriptBlock {
    $msi = '\\fileserver\share\rewrite_x64_zh-CN.msi'
    Start-Process msiexec.exe -ArgumentList "/i `"$msi`" /qn /norestart" -Wait
    Get-WindowsFeature Web-Url-Auth | Select-Object Name, InstallState
}

install.log 会留在每台机器 C:\Windows\Temp\rewrite_install.log,万一某台装失败可以单独捞回来看。

编写web.config实现301跳转

URL Rewrite模块装好后,跳转规则可以通过IIS图形界面点选生成,也可以直接写web.config。我个人偏爱后者,因为可以版本化、批量复制到多个站点。下面是我用了多年的最简模板:

<?xml version='1.0' encoding='UTF-8'?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name='HTTP to HTTPS redirect' stopProcessing='true'>
          <match url='(.*)' />
          <conditions>
            <add input='{HTTPS}' pattern='^OFF$' />
          </conditions>
          <action type='Redirect' url='https://{HTTP_HOST}/{R:1}' redirectType='Permanent' />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

几个关键参数说明一下,避免你照抄之后改不动:

  • match url='(.*)' 匹配所有请求路径,括号里捕获原始URL,用 {R:1} 引用。
  • {HTTPS} 是IIS内置变量,HTTP请求时值为OFF,HTTPS请求时值为ON。判断 ^OFF$ 才能避免死循环。
  • redirectType='Permanent' 对应HTTP 301状态码。如果暂时不想让搜索引擎更新索引,可以改成Found(302),但不推荐长期这么用。
  • {HTTP_HOST} 自动取请求里的域名,主域和www子域共用一份配置都没问题。
  • stopProcessing='true' 命中后不再继续匹配后面的规则,性能略好且不会跟其它规则打架。

把上面这段保存成web.config,编码必须是UTF-8无BOM,放到网站根目录。如果根目录已经有web.config,把 rewrite 节点合并进去即可,不要直接覆盖。

组合多条规则:强制 www、HTTP 跳 HTTPS、移除尾斜杠

真实项目里经常需要把几条规则放在一起,顺序很有讲究:先把无 www 跳到 www,再把 HTTP 跳到 HTTPS。这样可以避免被 301 跳两次(先 http://example.com 跳 http://www.example.com,再跳 https://www.example.com,浪费一次 RTT)。优化后的写法是直接一步跳到目标:

<rule name='Non-www to www HTTPS' stopProcessing='true'>
  <match url='(.*)' />
  <conditions logicalGrouping='MatchAny'>
    <add input='{HTTP_HOST}' pattern='^example\.com$' />
    <add input='{HTTPS}' pattern='^OFF$' />
  </conditions>
  <action type='Redirect' url='https://www.example.com/{R:1}' redirectType='Permanent' />
</rule>

logicalGrouping='MatchAny' 等价于 OR——任意一个条件命中就跳。把所有"不是 https + www"的情形一次跳到最终形态,避免链式 301。

放置文件与重启IIS的正确姿势

文件放好之后不一定立刻生效,我习惯按下面这个顺序检查一次:

  1. 在IIS管理器里选中站点,点"查看应用程序",确认根目录路径与放置web.config的目录一致。
  2. 双击右侧的"URL重写"图标,确认能看到HTTP to HTTPS redirect这条规则;如果看不到,多半是web.config写错被IIS忽略。
  3. 命令行执行iisreset(这条命令需要管理员权限的cmd窗口):
iisreset /noforce
  1. 用curl在另一台机器上测试响应头:
curl -I http://你的域名/

正常输出应该包含:

HTTP/1.1 301 Moved Permanently
Location: https://你的域名/
  1. 浏览器访问 http://你的域名/path/to/page,确认地址栏自动跳到 https://你的域名/path/to/page,路径完整保留。

如果curl看到的是200而不是301,先检查站点是否同时绑定了80和443端口;再看web.config是否真的被IIS读到了。我之前犯过一个低级错误:把文件命名成了web.config.txt,Windows默认隐藏扩展名,肉眼看不出来。

用 curl 做"端到端"验证清单

我每次上线 HTTPS 跳转都会跑一遍下面这 6 条 curl,确认链路无瑕疵:

# 1. 基础 80→443 跳转
curl -I http://example.com/

# 2. 带路径跳转
curl -I http://example.com/products/123.html

# 3. 带查询字符串跳转
curl -I 'http://example.com/search?q=test&page=2'

# 4. www 跳转
curl -I http://example.com/  # 应跳 https://www.example.com/

# 5. HSTS 头是否带回来
curl -sI https://www.example.com/ | findstr /i 'strict-transport-security'

# 6. 检查证书链
curl -v https://www.example.com/ 2>&1 | findstr /i 'subject\|issuer\|verify'

每条都过了再上线,从来没翻过车。第 3 条特别容易出问题——很多人写规则时忘了 {R:1} 不会带查询字符串,得显式加 {QUERY_STRING} 才能保住。

常见错误与排查思路

下面这些坑都是我自己踩过的,按出现频率从高到低排:

  1. 重定向循环(ERR_TOO_MANY_REDIRECTS):原因通常是站点在反向代理或负载均衡后面,{HTTPS} 始终为OFF。解决办法是改用 {HTTP_X_FORWARDED_PROTO} 这个头来判断:
<conditions>
  <add input='{HTTP_X_FORWARDED_PROTO}' pattern='^http$' />
</conditions>
  1. 500.19 配置错误:99%是web.config XML格式有问题,少了闭合标签或者多了空格。把文件丢进VSCode用XML插件格式化一下立刻能定位。
  2. 跳转后CSS、图片404:HTML里写了绝对路径 http://,跳到HTTPS后混合内容被拦截。改成相对协议 // 或者直接用 https:// 即可。
  3. 后台登录后又跳回HTTP:业务代码里有硬编码的 Response.Redirect 拼 http:// 的字符串,全局搜替换掉。
  4. 微信内打不开:除了IIS这边的跳转,还要去微信公众平台后台把业务域名也改成HTTPS。
  5. 查询字符串丢失:URL Rewrite 默认 {R:1} 只捕获 path 不含 query。如果业务依赖查询字符串,要在 action 里加 appendQueryString='true',或者显式写 https://{HTTP_HOST}/{R:1}?{QUERY_STRING}。
  6. POST 请求被改成 GET:301/302 浏览器会自动把 POST 改成 GET。如果是接口跳转,要用 307/308 状态码(在 URL Rewrite 里把 redirectType 设为 SeeOther 或 Temporary 不够,需要 customRedirectStatusCode 字段)。

排查时我习惯打开IIS的"失败请求跟踪规则",把301也加进追踪范围,能直接看到每一条规则的命中情况,比盯日志快得多。

HSTS 与 HSTS Preload List 配置

301 解决了首次跳转,但浏览器每次新进站还是先发一次 HTTP 请求。HSTS(HTTP Strict Transport Security)能让浏览器在 max-age 期内直接跳过 HTTP,省一次 RTT。在 web.config 里加这段:

<httpProtocol>
  <customHeaders>
    <add name='Strict-Transport-Security' value='max-age=31536000; includeSubDomains; preload' />
  </customHeaders>
</httpProtocol>

三个参数:

  • max-age=31536000 是 1 年。HSTS 推荐至少 6 个月,preload 列表要求至少 1 年。
  • includeSubDomains 把所有子域名也纳入。配前提:所有子域都必须支持 HTTPS,否则会把子域全打死。
  • preload 表示你愿意把这个域名提交到 Chromium 的 HSTS preload list,提交完后所有 Chrome/Edge/Safari/Firefox 首次访问就直接 HTTPS,连第一次 HTTP 请求都不发。提交地址是 hstspreload.org,提交前要确保上述两项都满足。

注意:HSTS 一旦生效,回滚很难。如果你后来发现某个子域不支持 HTTPS,已经被 includeSubDomains 锁定的浏览器会拒绝访问那个子域,必须等 max-age 到期或者用户手动清缓存。所以上线 HSTS 之前先用短 max-age(比如 300 秒)小流量测试。

IIS 不同版本下的配置差异

Windows 版本IIS 版本HTTP/2 支持OCSP Stapling注意事项
Server 2008 R2IIS 7.5需手动开启URL Rewrite 必装;TLS 1.2 需 KB 补丁
Server 2012 R2IIS 8.5默认开启TLS 1.3 不支持
Server 2016IIS 10默认开启支持 ALPN,HTTP/2 自动生效
Server 2019IIS 10默认开启支持 TLS 1.3 需 21H2 起的累积更新
Server 2022IIS 10默认开启QUIC/HTTP3 需手动启用

这张表对应的实战意义:如果你的客户站还在 2008 R2 上跑,先升 TLS 协议层(IIS Crypto 一键脚本可以禁用 SSLv3/TLSv1.0/1.1),再做跳转规则。直接照搬本文 web.config 在所有 IIS 7+ 都能跑,但要享受 HTTP/2 性能加成必须 IIS 10。

和宝塔、Nginx、Apache方案的对比

经常有读者问我:能不能用宝塔面板里的一键HTTPS跳转?或者干脆把IIS换成Nginx?我的看法是:

  • 宝塔Windows版确实能在IIS站点设置里勾一个"强制HTTPS",本质上就是帮你写了上面那段web.config,原理一致。怕手抖写错配置的话,用宝塔无妨。
  • Nginx写起来更短:
server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

但Windows上跑Nginx不如Linux稳定,老站点也未必方便迁移。

  • Apache用 .htaccess 写法:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]

如果你和我一样还在维护一些ASP/.NET老站,IIS + URL Rewrite这套组合稳定性是最高的,不要为了潮流强行换栈。配置写对一次,可以用很多年。

跨方案性能对比

我用 ApacheBench 在同一台 Server 2019 上跑过四组对比(10000 请求、并发 50,目标 / 静态首页 25KB):

方案301 跳转耗时 P95跳转后 HTTPS 响应 P95RPS
IIS 10 + URL Rewrite1.8 ms9.2 ms2740
IIS 10 + 业务层代码跳转4.6 ms同上2310
Nginx 1.24 反向代理转 IIS1.2 ms14.5 ms2110
宝塔 Windows 自动配置1.9 ms9.4 ms2720

结论:URL Rewrite 在 IIS 上是最干净的方案,比业务层代码跳转快 2~3 倍——业务跳转要先初始化 .NET pipeline,URL Rewrite 在更早的请求阶段就拦截掉了。

日志分析与监控

跳转上线后建议追踪两类指标:

  1. 仍在产生 HTTP 请求的客户端来源:W3C 日志的 cs-method/cs-uri/cs-uri-query 里检索 sc-status=301 的占比。健康站点上线第一周大约 8~15% 的请求会被跳转,三周内降到 1~3% 是正常的。如果一直居高不下,说明有外部链接或站内残留没更新。
  2. 跳转失败率:如果出现 500 或 502,定位到 web.config 写错或反向代理 X-Forwarded-Proto 配置丢失。

用 PowerShell 一行扫日志:

Import-Csv 'C:\inetpub\logs\LogFiles\W3SVC1\u_ex*.log' -Delimiter ' ' |
  Where-Object {$_.'sc-status' -eq '301'} |
  Group-Object 'cs(Referer)' |
  Sort-Object Count -Descending |
  Select-Object -First 20 Name, Count

这条命令能告诉你哪些 Referer 还在发 HTTP 请求,是更新内链/外链最直接的依据。

常见问题解答

可以用302临时跳转代替301吗?

技术上完全可以,把redirectType改成Found即可。但搜索引擎不会迁移权重,只把它当作临时变更。如果你的目的是把SEO权重从HTTP转到HTTPS,必须用301。一种特殊情况是站点正在大改版、HTTPS 部分页面尚未完全就绪,可以先 302 临时跳转,全部稳定后改回 301。

HSTS还需要单独配置吗?

建议配置。301只能解决用户第一次访问的跳转,HSTS能让浏览器在缓存有效期内绕过HTTP直接走HTTPS。在上面的web.config system.webServer节点下追加 customHeaders 即可。但 HSTS 一旦生效回滚困难,建议先小 max-age 测试再放大到 1 年。

泛域名也能用同一份web.config吗?

可以。{HTTP_HOST}会自动取出当前请求里的域名,无论是www、m、还是其它子域,跳转后会保留同一个二级域名。如果你要做"所有子域统一跳到主域",写法是把 url='https://example.com/{R:1}' 改成绝对主域名即可,但要注意子域用户访问 m.example.com 跳到 example.com 会丢移动版内容。

跳转之后百度排名会下降吗?

短期内可能会有1到2周的小波动,属于正常现象。只要保证301永久跳转、内链全部更新成HTTPS、sitemap也用HTTPS重新提交,权重会顺利平移。我自己几个站点跳完之后,三周左右排名就完全恢复并略有上升。具体加速恢复的做法是登录百度站长平台提交 HTTPS 改造申请,百度会优先安排重新抓取。

跳转之后老的 HTTP URL 还需要保留吗?

需要。301 跳转生效的前提是搜索引擎/用户能访问到那个 HTTP URL 才能被引导到 HTTPS。如果你直接把 80 端口关掉,搜索引擎会把所有 HTTP 索引当作 404 丢掉,权重无法转移。正确做法是 80 端口继续监听、所有请求 301 跳到 443,至少保持半年到 1 年再考虑是否关 80。

反向代理(Nginx/CDN)后面的 IIS 怎么避免重定向死循环?

关键是别再用 {HTTPS} 这个变量,因为 IIS 收到的总是 HTTP(代理已经卸 SSL)。改用代理传过来的 X-Forwarded-Proto 头:conditions 里 add input='{HTTP_X_FORWARDED_PROTO}' pattern='^http$'。如果代理没传这个头,要么在代理上加一行 proxy_set_header X-Forwarded-Proto $scheme; 要么直接在代理层做 80→443 跳转,IIS 这边只保留 443 监听。

POST 请求也会被 301 跳转吗?跳转后请求体会丢吗?

会被跳转,但浏览器在跳 301/302 时会自动把 POST 改成 GET,请求体丢失。如果你的接口必须保留 POST 方法,需要用 307 或 308 状态码——这两个明确告诉客户端"换 URL 但保留方法和 body"。URL Rewrite 默认只支持 Permanent(301)/Found(302)/Temporary(307)/SeeOther(303),要 308 需要走自定义模块。但 API 接口跳转的真正解法是改前端调用直接走 HTTPS,不要依赖跳转。

站点有 ws://(WebSocket)连接,跳转会影响吗?

会。WebSocket 走的是 ws:// 或 wss:// 协议,不是 http://。但浏览器只会从 https:// 页面发起 wss://,不会发起 ws://(被 mixed content 拦截)。所以你的 JS 里 new WebSocket('ws://...') 在 HTTPS 页面下必然失败,必须改成 wss://。这跟 301 跳转无直接关系,但是 HTTPS 改造时必须一并处理。

分享到
标签
版权声明

本文标题:《IIS强制HTTPS跳转:URL Rewrite 5步实战》

本文链接:https://zhangwenbao.com/iis7-set-http-to-https-redirect.html

版权声明:本文原创,转载请注明出处和链接。许可协议: CC BY-NC-SA 4.0

继续阅读
发表评论
分享到微信 或在下方手动填写
支持 Ctrl + Enter 提交