解码 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-处理库。
我的应用程序处理 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-处理库。