URL小写规范化
我希望编写一个HTTP模块,将URL转换为小写。我的第一次尝试忽略了国际字符集,效果非常好:
// Convert URL virtual path to lowercase
string lowercase = context.Request.FilePath.ToLowerInvariant();
// If anything changed then issue 301 Permanent Redirect
if (!lowercase.Equals(context.Request.FilePath, StringComparison.Ordinal))
{
context.Response.RedirectPermanent(...lowercase URL...);
}
土耳其测试(国际文化):
那么对于非en-US文化的地区呢?我参考了土耳其测试来设计一个测试URL:
http://example.com/Iıİi
这个小巧的瑰宝摧毁了转换URL大小写简单的想法!它的小写和大写版本分别为:
http://example.com/ııii
http://example.com/IIİİ
为了使土耳其URL的大小写转换正常工作,我首先需要将ASP.NET的当前区域设置为土耳其:
<system.web>
<globalization culture="tr-TR" />
</system.web>
接下来,我需要修改代码以使用当前区域设置进行大小写转换:
// Convert URL virtual path to lowercase
string lowercase = context.Request.FilePath.ToLower(CultureInfo.CurrentCulture);
// If anything changed then issue 301 Permanent Redirect
if (!lowercase.Equals(context.Request.FilePath, StringComparison.Ordinal))
{
context.Response.RedirectPermanent(...);
}
等等!StringComparison.Ordinal
还能用吗?还是应该使用StringComparison.CurrentCulture
?我真的不确定哪个是正确的!
文件名:情况更糟!
即使上面的方法可以解决问题,使用当前区域设置进行大小写转换会破坏NTFS文件系统!假设我有一个名为Iıİi.html
的静态文件:
http://example.com/Iıİi.html
尽管Windows文件系统是不区分大小写的,但它并不使用语言文化。将上述URL转换为小写会导致404 Not Found,因为文件系统不认为这两个名称相同:
http://example.com/ııii.html
文件名的正确大小写转换?谁知道?!
在MSDN文章《使用.NET Framework中的字符串的最佳实践》中,有一条注释(大约在文章中部):
注意:文件系统、注册表键和值以及环境变量的字符串行为最好用StringComparison.OrdinalIgnoreCase表示。
什么?最好用表示?这就是C#中我们能做到的最好吗?那么正确的大小写转换是什么呢?谁知道?!!?我们只能说使用上述内容的字符串比较可能大部分情况下都有效。
总结:两种大小写转换:静态/动态URL
- 我们已经看到静态URL——具有与文件系统中真实目录/文件匹配的文件路径的URL——必须使用未知的大小写转换,该转换仅由
StringComparison.OrdinalIgnoreCase
“最好表示”。请注意,没有string.ToLowerOrdinal()
方法,因此很难确切地知道哪种大小写转换等同于OrdinalIgnoreCase
字符串比较。使用string.ToLowerInvariant()
可能是最好的选择,但它会破坏语言文化。 - 另一方面,动态URL——文件路径与磁盘上的真实文件不匹配(映射到您的应用程序)的URL——可以使用
string.ToLower(CultureInfo.CurrentCulture)
,但它会破坏文件系统匹配,并且不清楚可能会破坏此策略的边缘情况。
因此,似乎首先需要检测URL是静态还是动态,然后选择两种转换方法之一。对于静态URL,如何更改大小写而不破坏Windows文件系统仍存在不确定性。对于动态URL,使用区域设置进行大小写转换是否会同样破坏URL仍有疑问。
哇!有人有这个混乱的解决方案吗?还是我应该闭上眼睛,假装一切都是ASCII?
.ToLowerASCII()
。.ToLowerInvariant()
则会远远超出范围并破坏许多国际字符。我相信目前没有100%的解决方案。 - Kevin P. RiceAccept-Language
。CurrentCulture
仅指服务器端应用程序的配置(除非您使其跟踪Accept-Language
)。人们会期望具有土耳其 URL 的服务器设置为该文化,尽管我想在一台机器上存在多个文化 URL 的噩梦场景可能会出现。也许 John 只转换 ASCII 字符是正确的。 - Kevin P. RiceAccept-Language
)保证用户的文化。这是一个判断性的问题。 - Kevin P. Rice