解码 URL 中的变音符号(或复合编码与预组合编码)

Decoding umlauts in URLs (or composite vs precomposed encoding)

我的应用程序处理 URL 秒。

一个例子如下:

https://127.0.0.1/Datei_Verz._Änderung.gif

浏览器发送的是:

https://127.0.0.1/Datei_Verz._%C3%84nderung.gif

当它未转义时(使用 AtlUnescapeUrl),%C3 和 %84 被视为不同的字符,所以我最终得到:

https://127.0.0.1/Datei_Verz._Änderung.gif

因此 unescape 无法识别浏览器发送的是复合字符而不是预组合字符(使用 MSDN 中的解释)。

理想情况下,浏览器会用单个 Unicode 代码点拉丁大写字母 A WITH DIAERESIS (U+00C4) 表示 Ä 我认为在 URL.

中可能是 %00C4

那么如何解码初始 URL?

这与 Unicode 规范化无关(预组合字符与分解字符序列)。只是字节编码错误的情况。

Ideally the browser would have represented Ä by the single Unicode code point LATIN CAPITAL LETTER A WITH DIAERESIS (U+00C4) which I assume could have been %00C4 in the URL.

不是:URL-编码是一种基于字节的编码; %-escapes 严格来说是两位数字(一个字节),因此 %00C4 将是一个零字节,后跟文字字符 C4.

没有用一个转义序列覆盖一个代码点的 % 编码。 Unicode URL 组件在转义为 %nn 序列之前必须编码为字节。

%C4 将是基于 ISO-8859-1 或代码页 1252 的网络应用程序 Ä 的编码,但大多数网络应用程序今天使用的编码(并且由IRI 标准)是 UTF-8。 %C3%84Ä 在 UTF-8 中的正确编码。

不幸的是,在 IRI 出现之前,ATL 是一个可悲的旧库。当它看到非 ASCII 转义序列时,它会使用您机器的特定于区域设置的默认 (ANSI) 代码页将它们解码为 Unicode,这绝不是 UTF-8。对于西欧 Windows 安装,您将获得代码页 1252,其中 %C3%84 表示两个字符 Ä.

(这可能是一个错误。在 atlutil.h 的版本中,我必须提交前面的评论,说使用什么编码并不重要,因为没有非 ASCII 字符,对于上面 AtlEscapeUrl 中的代码是正确的,它是不小心复制粘贴的,但对于 AtlUnescapeUrl 完全不是这样。这似乎意味着 ATL escape 和 unescape 函数不使用相同的编码,所以不要往返...哎呀。)

要解决这个问题,您可以自己处理 Unicode 位。不是调用 AtlUnescapeUrl 的 Unicode (LPWSTR) 版本,而是使用 UTF-8 编码 (MultiByteToWideChar CP_UTF8) 将输入的 Unicode 字符串转换为字节字符串,然后调用字节 (LPSTR) ) 版本的 AtlUnescapeUrl 在字节串上,并再次解码 (WideCharToMultiByte CP_UTF8).

或者选择另一个损坏较少的 URL-处理库。