TL;DR
<rule name="AddTrailingSlash" stopProcessing="true">
<match url="^([^/]+:\/\/[^/#?]+|[^?#]+?)\/?((?:[^/?#]+\.[^/?#]+)?(?:[?#].*)?$)" />
<action type="Redirect" url="{R:1}/{R:2}" redirectType="Permanent" />
</rule>
IIS use ECMAScript,您可以在此处试用:https://regexr.com/6ele7
更新
<rule name="AddTrailingSlash" stopProcessing="true">
<match url="^([^/]+:\/\/[^/#?]+|[^?#]+\/[^/.?#]+)([?#].*)?$" />
<action type="Redirect" url="{R:1}/{R:2}" redirectType="Permanent" />
</rule>
尝试一下:https://regexr.com/6fk3g
http://127.0.0.1 --> http://127.0.0.1/
https://localhost --> https://localhost/
https://localhost? --> https://localhost/?
https://localhost/ --> https://localhost/
https://my.site.com --> https://my.site.com/
https://my.site.com:443? --> https://my.site.com:443/?
https://my.site.com/ --> https://my.site.com/
https://my.site.com/about.php --> https://my.site.com/about.php
https://my.site.com/about.php? --> https://my.site.com/about.php?
https://my.site.com/about --> https://my.site.com/about/
https://my.site.com/about? --> https://my.site.com/about/?
https://my.site.com/about/ --> https://my.site.com/about/
https://my.site.com/about/? --> https://my.site.com/about/?
https://my.site.com/about?query --> https://my.site.com/about/?query
https://my.site.com/about/?query --> https://my.site.com/about/?query
https://my.site.com/about.php?query --> https://my.site.com/about.php?query
https://my.site.com/about#hash --> https://my.site.com/about/#hash
https://my.site.com/about/#hash --> https://my.site.com/about/#hash
https://my.site.com/about.php#hash --> https://my.site.com/about.php#hash
https://my.site.com/about?query#hash --> https://my.site.com/about/?query#hash
https://my.site.com/about/?query#hash --> https://my.site.com/about/?query#hash
https://my.site.com/folder.name/about?query --> https://my.site.com/folder.name/about/?query
https://my.site.com/about?query#hash:http://test.com?q --> https://my.site.com/about/?query#hash:http://test.com?q
说明(全部)
^([^?#]+?)\/?([?#].*)?$
第 1 组: ^ 首先,[^?#] 除?/# 之外的任何字符,多但懒惰+?(尽可能先停止,通过查看next)
忽略: \/? 那么如果/ 存在与否
第2组: [?#] = ?/@987654359 @ 和 .* 旁边的任何字符直到 $ 结束,(...)? 如果存在
效果很好。 但是它不会正确处理:
https://my.site.com/about.php?query --> https://my.site.com/about.php/?query !!!
所以让我们添加一个例外...
-
2 级 - 如果我们将可能的文件名
Name.name.name.ext 作为 Group #2 怎么办?
^([^?#]+?)\/?((?:[^/?#]+\.[^/?#]+)?(?:[?#].*)?)$
(?:...)非捕获组
([^/?#]+\.[^/?#]+)?查找任何可能的文件名或(?:[?#].*)?任何可能的查询或锚字符串
现在一切正常,除了这个:
https://my.site.com? --> https://my.site.com? !!!
所以我们需要Group #1
中的另一个例外
^([^/]+:\/\/[^/#?]+|[^?#]+?)\/?((?:[^/?#]+\.[^/?#]+)?(?:[?#].*)?$)
(...|...) 替代
[^/]+:\/\/[^/#?]+ 首先检查(不是懒惰的)任何像...://... 这样的模式直到不存在/ # ??
现在效果很好!
+ 解释(考虑)
-
4 级 - 如果我们只在第一组中添加 Not-Accepting
. 和 / 字符集以匹配考虑的 URI 并忽略其他 URI,该怎么办?
^([^/]+:\/\/[^/#?]+|[^?#]+\/[^/.?#]+)([?#].*)?$
\/[^/.?#]+ 检查最后一个/ 之后的字符集是否不是/.?#
现在它更小更快了!
分析其他方法
由于@károly-szabó 回答得很好here,我们可以寻找匹配的模式,而不是寻找 Not-Accepted 字符集。
因此,如果我们想以更简单的方式使用该方法(2 组)(+ 一些小的优化),则正则表达式将是:
^(https?:\/\/[\w.:-]+\/?(?:[\w.-]+\/)*[\w-]+(?!\/))([?#].*)?$
但是URI pathAccepted characters更多。
因此,该正则表达式的更广泛版本可以是:
^(https?:\/\/[\w.:-]+\/?(?:[\w!#-)+-.;=@~]+\/)*[\w!#-);=@~+,-]+(?!\/))([?#].*)?$
在这里试试:https://regexr.com/6elea
注意:仍然“允许使用multibyte Unicode 作为域名”,但我在此方法中忽略了这一点。
附言
实际上我认为我们不应该在 IIS 上重写它,原因如下:
- 锚字符
# 可以是文件夹名称的一部分(%23)
- 文件名不能有扩展名
- IIS/浏览器通常会(/应该)处理锚点/查询
参考:
我的意思是:
https://my.site.com/ --> (=Call root)
https://my.site.com/about --> (=Call root > Folder/File name about)
https://my.site.com/about/ --> (=Call root > Folder name about)
https://my.site.com/about?query --> (=Call root > Folder/File name about + Query)
https://my.site.com/about/?query --> (=Call root > Folder name about + Query)
https://my.site.com/about.php?query --> (=Call root > File name about.php + Query)
[When browser strip it:]
https://my.site.com/about#hash --> (=Call root > Folder/File name about + Anchor)
https://my.site.com/about/#hash --> (=Call root > Folder name about + Anchor)
https://my.site.com/about.php#hash --> (=Call root > File name about.php + Anchor)
[If not?]
https://my.site.com/folder#name/?query#hash
https://my.site.com/folder.name/about.php?query=one/two