【问题标题】:How can I convert a string to the idna coded, encoding with 'idna' coded failed如何将字符串转换为 idna 编码,使用 'idna' 编码的编码失败
【发布时间】:2020-02-15 03:15:49
【问题描述】:

我有一个字符串,它应该是 python 后续步骤中的 stmp 服务器。

字符串是(很少匿名):

outlook-stg.d-a-tf.de/mapi/emsmdb/?MailboxId=cf27be4f-8605-40e4-94ab-d8cea3cc03bc@test.com

确定错误是:

UnicodeError:使用“idna”编解码器编码失败(UnicodeError:标签 空或太长)

我的理解是我想如何寻址服务器的名称有问题:label empty or too long - python urllib2

但是我怎样才能把它转换成正确的格式呢?我也试过了:Encoding with 'idna' codec failed in RethinkDB

使用此代码:.encode("idna") 但这也是同样的错误。

【问题讨论】:

  • 如果有帮助,请查看我的回复,但我担心“我有一个字符串,它应该是 Python 后续步骤中的 stmp 服务器”可能存在一些歧义。和“但是我怎样才能把它转换成正确的格式呢?”所以我在写回复时做了一些假设。如果您可以为您的问题或一些代码添加额外的上下文,我们也许可以改进答案。

标签: python encoding smtp


【解决方案1】:

IDNA 是一种用于对域名或主机名进行编码的算法。您提供的示例是一个 URL,因此它包含无法在域名中使用的字符,因此无法编码,因此您的错误。

您需要将域名(主机)名称与其他名称分开,仅对其应用 IDNA(但在您的示例中无用,因为您的主机名已经是纯 ASCII),然后重建您的 URL。

您引用的具体错误来自以下事实:由于 IDNA 处理名称,根据 DNS 定义,它在标签级别工作。标签是点之间的东西,所以第一步是分割东西。 然后以这种方式处理您的字符串:

  1. outlook-stg
  2. d-a-tf
  3. de/mapi/emsmdb/?MailboxId=cf27be4f-8605-40e4-94ab-d8cea3cc03bc@test
  4. 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
否则。

因此,根据您的需要,您应该:

  1. 将您的字符串解析为 URI/IRI(使用适当的库,不要指望自己使用正则表达式正确完成)
  2. 现在您已经有了主机名部分,您可以根据需要在其上应用 IDNA(但 URI/IRI 解析库实际上可能已经为您完成了这项工作,所以请仔细检查)
  3. 如果需要,然后重建完整的 URI/IRI。

【讨论】:

  • 所以换句话说,这里的实际服务器名称只是outlook-stg.d-a-tf.de,如果没有额外的上下文,我们真的无法猜测其余部分应该如何使用(尽管 MAPI 名称模糊地暗示了一些 Microsoft暴行)。
  • @tripleee 是的,主机名是 outlook-stg.d-a-tf.de,如果您必须将 IDNA 应用于某物,那将是应用它的唯一部分(但在这里它会返回相同的结果,输入是所有 7 位 ASCII 已经是,所以在 IDNA 下没有变化)。我在回复中认为该字符串是一个 URL,如果是这样,IDNA 可能仅适用于它的主机名部分,而不适用于其他部分。 OP 有“我有一个字符串,它应该是 Python 后续步骤中的 stmp 服务器。”我不知道如何从该字符串中获得“smtp 服务器”,除了主机名。可能缺少某些上下文。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-08
  • 2019-01-24
  • 1970-01-01
  • 2019-05-06
  • 1970-01-01
  • 1970-01-01
  • 2016-10-01
相关资源
最近更新 更多