在Python 3中使用urllib时出现socket资源警告
我正在使用一个叫做 urllib.request.urlopen() 的方法,从我想测试的网络服务获取数据。
这个方法会返回一个 HTTPResponse 对象,我接着用 read() 方法来读取响应的内容。
不过,我总是看到一个关于未关闭的 socket 的资源警告,这个警告来自 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)做些什么,让它能干净地关闭这个 socket,我真的很想知道,因为这段代码是我单元测试的一部分;我不喜欢在任何地方忽略警告,尤其是在这里。
2 个回答
我也遇到过和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
附注:你也可以使用requests
库,虽然它在2019年时不是Python标准库的一部分,但它功能强大且易于使用:http://docs.python-requests.org/en/master/
我不知道这是否是正确的答案,但这确实是解决问题的一部分。
如果我在我的网络服务的响应中添加“connection: close”这个头信息,HTTPResponse对象似乎就能正常清理自己,而不会出现警告。
实际上,HTTP规范(http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html)中提到:
不支持持久连接的HTTP/1.1应用程序必须在每条消息中包含“close”连接选项。
所以问题出在服务器那边(也就是说,是我的错!)。如果你无法控制服务器发送的头信息,我也不知道该怎么办。