为了账号安全,请及时绑定邮箱和手机立即绑定

请求中的大写 URL 返回“名称无法解析”

请求中的大写 URL 返回“名称无法解析”

哆啦的时光机 2022-01-05 19:22:55
我想从带有大写字符的 URL 获取数据。URL 基于 docker 主机名。requests 总是Name does not resolve在它降低 URL 时返回。网址是http://gateway.Niedersachsen/api/bundeslaender。ping gateway.Niedersachsen有效但ping gateway.niedersachsen无效。我的 Python 请求代码:url = f'http://gateway.Niedersachsen/api/wfs/insertGeometry'r = requests.get(url)出现以下错误:requests.exceptions.ConnectionError: HTTPConnectionPool(host='gateway.niedersachsen', port=80): Max retries exceeded with url: /api/wfs/insertGeometry (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f5f5eb5a3c8>: Failed to establish a new connection: [Errno -2] Name does not resolve'))我的版本:$ python --versionPython 3.7.3> requests.__version__'2.21.0'
查看完整描述

1 回答

?
三国纷争

TA贡献1804条经验 获得超7个赞

RFC 3986第 6.2.2.1 节关于 URI 的说明:

[...]的方案和主机不区分大小写的,因此应被归一化到小写[...]。

恕我直言,您的名称解析行为不正确,似乎有一个与 Docker 网络区分大小写相关的未决问题,我认为这里正在使用。

requests, 分别 urllib3, 尊重 RFC 建议,至少对于 HTTP 方案连接。就requests目前而言,似乎有四个相关的地方将主机名转换为小写。

  1. urllib3的实用程序类Url,它在requests'PreparedRequest实例执行prepare_url方法时发挥作用。

  2. 通过映射_default_key_normalizer调用的函数PoolManagerkey_fn_by_scheme

  3. 如果您的主机名包含非 ASCII 字符,它也会通过IDNA 编码传递,但在您的示例中并非如此。

  4. urllib31.22 版还lower()调用了ConnectionPool基类初始值设定项中的主机名。_ipv6_host显然,此规范化已移至1.23 版的功能。

使用monkeypatching我似乎已经能够强制requests,resp。urllib3, 保留 URL 的主机名部分不变:

import functools

import urllib3


def _custom_key_normalizer(key_class, request_context):

    # basically a 1:1 copy of urllib3.poolmanager._default_key_normalizer

    # commenting out 

    # https://github.com/urllib3/urllib3/blob/master/src/urllib3/poolmanager.py#L84

    #context['host'] = context['host'].lower()


class ConnectionPool(object):

    def __init__(self, host, port=None):

        # complete copy of urllib3.connectionpool.ConnectionPool base class

        # I needed this due to my urllib3 version 1.22. 

        # If you have urllib3 >= 1.23 this is not necessary

        # remove the .lower() from 

        # https://github.com/urllib3/urllib3/blob/1.22/urllib3/connectionpool.py#L71

        self.host = urllib3.connectionpool._ipv6_host(host)


urllib3.util.url.NORMALIZABLE_SCHEMES = (None,)

# This is needed for urllib3 >= 1.23. The connectionpool module imports

# NORMALIZABLE_SCHEMES before we can patch it, so we have to explicitly patch it again

urllib3.connectionpool.NORMALIZABLE_SCHEMES = (None,)

urllib3.poolmanager.key_fn_by_scheme['http'] = functools.partial(_custom_key_normalizer, 

                                                                 urllib3.poolmanager.PoolKey)

# just for urllib3 < 1.23

urllib3.connectionpool.ConnectionPool = ConnectionPool


# do not use anything that would import urllib3 before this point    

import requests

url = f'http://gateway.Niedersachsen/api/wfs/insertGeometry'

r = requests.get(url)

我假设成功,因为我的错误消息显示连接池中使用的主机,仍然使用初始大写:


requests.exceptions.ConnectionError: HTTPConnectionPool(host='gateway.Niedersachsen', port=80): [...]

注意:直接

使用可能有更简单的方法urllib3;我没有研究过这个。

另外,如果有人知道使用 保留主机大写的更直接方法requests,请告诉我。


查看完整回答
反对 回复 2022-01-05
  • 1 回答
  • 0 关注
  • 179 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号