Я хотел бы ПОЛУЧИТЬ данные из URL-адреса с заглавными буквами. URL-адрес основан на имени хоста докера. запросы всегда возвращают Name does not resolve
, поскольку он понижает URL-адрес.
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'
Это невозможно из-за масштабирования службы шлюза. Несколько сервисов приводят к нескольким IP-адресам ?
RFC 3986 Раздел 6.2.2.1 говорит об URI:
[...] the scheme and host are case-insensitive and therefore should be normalized to lowercase [...].
ИМХО, ваше разрешение имени ведет себя неправильно, и, похоже, существует открытый проблема, связанный с чувствительностью к регистру для сети Docker, который, как я полагаю, здесь используется.
requests
, соотв. urllib3
, соблюдает рекомендации RFC, по крайней мере, для соединений по схеме HTTP. Что касается requests
, кажется, есть четыре подходящих места, где имена хостов преобразуются в нижний регистр.
urllib3
Url
, который вступает в игру, когда экземпляр requests
' PreparedRequest
выполняет метод prepare_url
._default_key_normalizer
, которая вызывается PoolManager
через отображение key_fn_by_scheme
urllib3
версия 1.22 также имела lower()
вызов имени хоста в инициализаторе базового класса ConnectionPool
. Эта нормализация была перенесена в функцию _ipv6_host
, по-видимому, начиная с версии 1.23.Кажется, что с помощью monkeypatching мне удалось заставить 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
, пожалуйста, дайте мне знать.
Выглядит хорошо, но я не смог запустить это. Я использую urllib3
версию 1.24.1 и поэтому пропустил часть вашего кода. Я использовал обычный и подготовленные запросы для отладки, и мой подготовленный запрос имел правильный (верхний регистр) URL-адрес. Однако фактический запрос завершился с той же начальной ошибкой. Не знаю, что не так...
@Felix Я пропустил, что нормализация в ConnectionPool
базовом классе была взолнованный, а не удаленный, в urllib3
версии 1.23. Вам также необходимо пропатчить NORMALIZABLE_SCHEMES
на уровне модуля connectionpool
: urllib3.connectionpool.NORMALIZABLE_SCHEMES = (None,)
. Я обновил свой ответ.
Как насчет того, чтобы заменить
gateway.Niedersachsen
на его IP?