IDNA 是一种用于对域名或主机名进行编码的算法。您提供的示例是一个 URL,因此它包含无法在域名中使用的字符,因此无法编码,因此您的错误。
您需要将域名(主机)名称与其他名称分开,仅对其应用 IDNA(但在您的示例中无用,因为您的主机名已经是纯 ASCII),然后重建您的 URL。
您引用的具体错误来自以下事实:由于 IDNA 处理名称,根据 DNS 定义,它在标签级别工作。标签是点之间的东西,所以第一步是分割东西。
然后以这种方式处理您的字符串:
outlook-stg
d-a-tf
de/mapi/emsmdb/?MailboxId=cf27be4f-8605-40e4-94ab-d8cea3cc03bc@test
com
并且DNS中的标签不能超过63个字节。您的第三个字符串,即使现在不考虑它包含在域名中永远不会出现的不允许字符(例如@),即使使用 IDNA 编码,也是 68 个字节长,因此您得到的确切错误。
如果我人为地缩小它,我会得到另一个错误,正如基于上述解释的预期:
>>> print(idna.encode('outlook-stg.d-a-tf.de/mapi/emsmdb/?MId=cf27be4f-8605-40e4-94ab-d8cea3cc03bc@test.com'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.7/site-packages/idna/core.py", line 358, in encode
s = alabel(label)
File "/usr/local/lib/python3.7/site-packages/idna/core.py", line 270, in alabel
ulabel(label)
File "/usr/local/lib/python3.7/site-packages/idna/core.py", line 304, in ulabel
check_label(label)
File "/usr/local/lib/python3.7/site-packages/idna/core.py", line 261, in check_label
raise InvalidCodepoint('Codepoint {0} at position {1} of {2} not allowed'.format(_unot(cp_value), pos+1, repr(label)))
idna.core.InvalidCodepoint: Codepoint U+002F at position 3 of 'de/mapi/emsmdb/?mid=cf27be4f-8605-40e4-94ab-d8cea3cc03bc@test' not allowed
(U+002F 是/ 当然是域名中不允许的另一个字符,因此在 IDNA 编码期间被拒绝)
请注意,在 URL 的其他部分(即路径)中也有编码“非 ascii 字符”的规则,这就是为什么现在最高管理标准是 IRI:RFC 3987
它说,即使以一种令人费解的方式,也正是上述内容:
将 IRI 的 ireg-name 部分替换为使用转换的部分
[RFC3490] 第 4.1 节中指定的 ToASCII 操作对每个
点分隔标签,并使用 U+002E (FULL STOP) 作为标签
分隔符,将 UseSTD3ASCIIRules 标志设置为 TRUE,并使用
标志 AllowUnassigned 设置为 FALSE 以创建 IRI 并设置为 TRUE
否则。
因此,根据您的需要,您应该:
- 将您的字符串解析为 URI/IRI(使用适当的库,不要指望自己使用正则表达式正确完成)
- 现在您已经有了主机名部分,您可以根据需要在其上应用 IDNA(但 URI/IRI 解析库实际上可能已经为您完成了这项工作,所以请仔细检查)
- 如果需要,然后重建完整的 URI/IRI。