URL-адрес в верхнем регистре в запросах возвращает «Имя не разрешается»

Я хотел бы ПОЛУЧИТЬ данные из 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'

Как насчет того, чтобы заменить gateway.Niedersachsen на его IP?

Waket Zheng 10.04.2019 10:17

Это невозможно из-за масштабирования службы шлюза. Несколько сервисов приводят к нескольким IP-адресам ?

Felix 10.04.2019 10:20
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
2
1 937
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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, кажется, есть четыре подходящих места, где имена хостов преобразуются в нижний регистр.

  1. Вспомогательный класс urllib3Url, который вступает в игру, когда экземпляр requests' PreparedRequest выполняет метод prepare_url.
  2. функция _default_key_normalizer, которая вызывается PoolManager через отображение key_fn_by_scheme
  3. если ваше имя хоста содержит символы, отличные от ASCII, это также кодировка прошел через IDNA, но в вашем примере это не так.
  4. 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 12.04.2019 15:05

@Felix Я пропустил, что нормализация в ConnectionPool базовом классе была взолнованный, а не удаленный, в urllib3 версии 1.23. Вам также необходимо пропатчить NORMALIZABLE_SCHEMES на уровне модуля connectionpool: urllib3.connectionpool.NORMALIZABLE_SCHEMES = (None,). Я обновил свой ответ.

shmee 13.04.2019 17:50

Другие вопросы по теме