在不破坏文件系统或文化的情况下,将URL规范化为小写?

Kev*_*ice 8 c# asp.net winapi

将URL规范化为小写

我希望编写一个将URL转换为小写的HTTP模块.我的第一次尝试忽略了国际字符集,效果很好:

// 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...);
}
Run Code Online (Sandbox Code Playgroud)

土耳其考试(国际文化):

但是除了en-US之外的其他文化呢?我提到土耳其测试提出测试网址:

http://example.com/I??i
Run Code Online (Sandbox Code Playgroud)

这个小阴险的宝石破坏了URL中的大小写转换很简单的想法!它的小写和大写版本分别是:

http://example.com/??ii
http://example.com/II??
Run Code Online (Sandbox Code Playgroud)

要将大小写转换为使用土耳其语URL,我首先必须将ASP.NET的当前文化设置为土耳其语:

<system.web>
    <globalization culture="tr-TR" />
</system.web>
Run Code Online (Sandbox Code Playgroud)

接下来,我不得不更改我的代码以使用当前文化进行大小写转换:

// 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(...);
}
Run Code Online (Sandbox Code Playgroud)

可是等等!将StringComparison.Ordinal仍然工作?或者我应该使用StringComparison.CurrentCulture?我真的不确定!

文件名:它变得多么糟糕!

即使以上工作,使用当前文化进行大小写转换会破坏 NTFS文件系统!假设我有一个名称为的静态文件I??i.html:

http://example.com/I??i.html
Run Code Online (Sandbox Code Playgroud)

即使Windows文件系统不区分大小写,它也不使用语言文化.将上面的URL转换为小写会导致404 Not Found,因为文件系统不会将这两个名称视为相等:

http://example.com/??ii.html
Run Code Online (Sandbox Code Playgroud)

文件名的正确大小写转换?谁知道?!

MSDN文章,在.NET Framework中使用字符串的最佳实践,有一个注释(大约在文章的一半):

注意: StringComparison.OrdinalIgnoreCase最能表示文件系统,注册表项和值以及环境变量的字符串行为.

咦?最好的代表??? 这是我们在C#中能做的最好的事情吗?那么正确的案例转换是什么以匹配文件系统?谁知道?!!?我们可以说的是,使用上面的字符串比较可能在大部分时间都有效.

摘要:两种案例转换:静态/动态URL

  1. 因此,我们已经看到静态URL ---具有与文件系统中的真实目录/文件匹配的文件路径的URL - 必须使用仅被"最佳表示"的未知大小写转换StringComparison.OrdinalIgnoreCase.请注意,没有string.ToLowerOrdinal()方法,所以很难确切知道转换等同于OrdinalIgnoreCase字符串比较的情况.使用string.ToLowerInvariant()可能是最好的选择,但它打破了语言文化.
  2. 另一方面,动态URL ---文件路径与磁盘上的真实文件(映射到您的应用程序)不匹配的URL--可以使用string.ToLower(CultureInfo.CurrentCulture),但它会破坏文件系统匹配,有些不清楚存在可能违反此策略的边缘情况.

因此,在选择两种转换方法之一之前,似乎案例转换首先需要检测URL是静态的还是动态的.对于静态URL,如何在不破坏Windows文件系统的情况下更改大小写是不确定的.对于动态URL,如果使用culture进行大小写转换会同样破坏URL,则会产生疑问.

呼!任何人都有这个烂摊子的解决方案?或者我应该闭上眼睛假装一切都是ASCII?

ric*_*ent 5

我会在这里挑战这个前提,即在尝试将URL自动转换为小写时有任何实用程序.

完整URL是否区分大小写完全取决于Web服务器,Web应用程序框架和基础文件系统.

您只能保证方案(http://等)和URL的主机名部分不区分大小写.请记住,不是所有的URL方案(filenews等),甚至还包括一个主机名.

其他一切可以区分大小写的服务器,包括路径(/),文件名,查询(?),片段(#),和权威信息(用户名/前的密码@mailto,http,ftp,和其他一些方案).


Jon*_*nna 2

你们有一些不相容的目标。

\n\n
    \n
  1. 具有文化敏感的大小写降低。如果土耳其语看起来很糟糕,您不想了解一些格鲁吉亚文字,不用介意它\xc3\x9f是大写的SS还是不太常见的SZ- 在任何一种情况下都有一个完整的大小写折叠,其中lower("\xc3\x9f")将匹配lower(upper("\xc3\x9f"))您需要的认为它至少相当于这些两个字符序列之一。一般来说,如果可能的话,我们的目标是折叠大小写而不是降低大小写(这里不可能)。

  2. \n
  3. 在非文化敏感的环境中使用它。URI 最终是不透明的字符串。以便他们可以具有人类可读的理解,这对于编码人员、用户、搜索引擎和营销人员等都是有用的,但它们的最终工作是通过直接区分大小写的比较来识别资源。

  4. \n
  5. 将其映射到 NTFS,它具有基于 $UpCase 文件中的映射的区分大小写的功能,它通过比较单词的大写形式来实现这一点(至少它不必决定是否\xce\xa3小写)案件到\xcf\x83\xcf\x82,以文化不敏感的方式。

  6. \n
  7. 大概在搜索引擎优化和人类可读性方面做得很好。这很可能是您最初目标的一部分,但是虽然这不是很容易阅读或解析,但它对于人和机器来说都更容易。折叠案例会丢失信息。

  8. \n
\n\n

我建议采用不同的方法。

\n\n
    \n
  1. 从起始字符串开始,无论它是什么、来自何处(NTFS 文件名、数据库条目、web.config 中的 HttpHandler 绑定)。将其作为您的规范形式。无论如何,都有规则要求人们应该根据某种规范形式创建这些字符串,并可能在可能的情况下强制执行它,但是如果有什么事情违反了你的规则,那么无论多少,都接受它作为该资源的官方规范名称你不喜欢它。

  2. \n
  3. 规范名称应尽可能成为外界“看到”的唯一名称。这可以通过编程方式强制执行,或者只是最佳实践,因为事后使用 301 进行规范化并不能解决外部实体在取消引用 URI 之前不知道您这样做的问题。

  4. \n
  5. 收到请求后,根据它将如何使用进行测试。因此,虽然您可以选择在您自己使用所谓的“静态”URI 执行资源查找的情况下使用(或不使用)特定区域性,但您的逻辑可以故意遵循 NTFS 的逻辑,只需使用 NTFS 执行以下操作即可:工作:

    \n\n
      \n
    1. 查找映射文件,暂时忽略大小写问题。
    2. \n
    3. 如果不匹配则 404,谁关心大小写?
    4. \n
    5. 如果找到,则进行区分大小写的序数比较,如果不匹配,则将 301 转换为区分大小写的映射。
    6. \n
    7. 否则,请照常进行。
    8. \n
  6. \n
\n\n

编辑:

\n\n

在某些方面,域名问题更为复杂。IDN 规则必须涵盖更多问题,而 man\xc5\x93uver 的空间却更少。然而,至少就案例规范化而言,它也更简单。

\n\n

(我将忽略是否www.使用的规范化等。虽然我猜这是同一工作的一部分,但它扩大了范围,我们最终可能会在如果我们不停下来的话,我们:)

\n\n

IDN 在 RFC 3491 中定义了自己的大小写规范化(以及一些其他形式的规范化)规则。如果您要根据大小写规范化域名,请遵循该规则。

\n\n

回答起来既美好又简单,不是吗?:)

\n\n

在某种程度上压力也较小,因为虽然搜索引擎必须认识到这一点http://example.net/thisisapath并且http://example.net/thisIsAPath是相同的资源,但它们也必须认识到它们可能是不同的,这就是规范化的所有 SEO 优势所在其中之一(无论是哪一个)来自。

\n\n

然而,他们知道这一点,example.net并且EXAMPLE.NET不可能是不同的网站,因此在确保它们相同方面几乎没有 SEO 优势(对于缓存和历史列表之类的东西来说仍然很好,这些东西不会跳跃他们自己)。当然,问题仍然在于,www.example.net甚至maAndPasExampleEmporium.us可能是同一个站点,但同样,这远离了案例问题。

\n\n

还有一个简单的问题,大多数时候我们从来不需要处理超过几十个不同的域,所以有时更努力而不是更聪明地工作(即只需确保它们都设置正确并且不要\不以编程方式做任何事情!)可以做到这一点。

\n\n

最后要注意的是,不要规范化第三方 URI,这一点很重要。如果你改变路径,你最终可能会破坏事情(他们可能不会不区分大小写地对待它),并且你至少可能最终会破坏他们稍微不同的规范化。最好始终保持原样。

\n