Сокет ResourceWarning с использованием urllib в Python 3
Я использую urllib.request.urlopen() для получения из веб-службы, которую я пытаюсь проверить.
Это возвращает объект HTTPResponse, который я затем читаю (), чтобы получить тело ответа.
Но я всегда вижу ResourceWarning о незамкнутом сокете из socket.py
Вот соответствующая функция:
from urllib.request import Request, urlopen
def get_from_webservice(url):
""" GET from the webservice """
req = Request(url, method="GET", headers=HEADERS)
with urlopen(req) as rsp:
body = rsp.read().decode('utf-8')
return json.loads(body)
Вот предупреждение, которое появляется в выводе программы:
$ ./test/test_webservices.py
/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/socket.py:359: ResourceWarning: unclosed <socket.socket object, fd=5, family=30, type=1, proto=6>
self._sock = None
.s
----------------------------------------------------------------------
Ran 2 tests in 0.010s
OK (skipped=1)
Если я что-то могу сделать с HTTPResponse (или Request?), Чтобы он аккуратно закрыл свой сокет, я бы очень хотел знать, потому что этот код предназначен для моих модульных тестов; Я не люблю игнорировать предупреждения где угодно, но особенно не там.
1 ответ
Я не знаю, является ли это ответом, но это часть пути к ответу.
Если я добавлю заголовок "connection: close" к ответу от моих веб-сервисов, объект HTTPResponse, похоже, будет очищен должным образом без предупреждения.
И действительно, в спецификации HTTP ( http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html) сказано:
Приложения HTTP/1.1, которые не поддерживают постоянные соединения, ДОЛЖНЫ включать опцию "закрыть" в каждом сообщении.
Таким образом, проблема была на стороне сервера (т.е. моя вина!). Если у вас нет контроля над заголовками, поступающими с сервера, я не знаю, что вы можете сделать.
У меня была такая же проблема с urllib3
и я просто добавил контекстный менеджер для автоматического закрытия соединения:
import urllib3
def get(addr, headers):
""" this function will close the connection after a http request. """
with urllib3.PoolManager() as conn:
res = conn.request('GET', addr, headers=headers)
if r.status == 200:
return res.data
else:
raise ConnectionError(res.reason)
Обратите внимание, что urllib3
предназначен для того, чтобы иметь пул соединений и поддерживать соединения для вас. Это может значительно ускорить ваше приложение, если ему необходимо выполнить серию запросов, например, несколько обращений к бэкэнд-API.
Пожалуйста, прочитайте urllib3
Документация по пулам соединений здесь: https://urllib3.readthedocs.io/en/1.5/pools.html
PS вы также можете использовать requests
lib, которая не является частью стандартной библиотеки Python (на 2019 г.), но очень мощная и простая в использовании: http://docs.python-requests.org/en/master/