请求中的大写 URL 返回"Name does not resolve"



我想从带有大写字符的URL获取数据。该 URL 基于 docker 主机名。请求始终返回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 --version
Python 3.7.3
> requests.__version__
'2.21.0'

RFC 3986 第 6.2.2.1 节介绍了 URI:

[...

]方案和主机不区分大小写,因此应规范化为小写[...]。

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

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

  1. urllib3的实用程序类Url,当requests'PreparedRequest实例执行prepare_url方法时发挥作用。
  2. PoolManager通过key_fn_by_scheme映射调用的_default_key_normalizer函数
  3. 如果您的主机名包含非 ASCII 字符,它也会通过 IDNA 编码传递,但在您的示例中并非如此。
  4. urllib3版本 1.22 还对ConnectionPool基类初始值设定项中的主机名进行了lower()调用。显然,从 1.23 版开始,此规范化已移至_ipv6_host函数。

使用猴子补丁,我似乎已经能够胁迫requests,或者。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保留主机大写的更直接的方法,请告诉我。

相关内容

最新更新