如何解决Tornado 测试 - 通过备用 IP
我在 Tornado 上遇到了一些非常奇怪的事情
from tornado.web import Application
from tornado.testing import AsyncHTTPTestCase
import requests
import tornado
from tornado.ioloop import IOLoop
class MyTest(AsyncHTTPTestCase):
def get_app(self):
return Application()
@tornado.testing.gen_test(timeout=30)
async def test_pass(self):
response = await IOLoop.current().run_in_executor(None,requests.get,"http://127.0.0.1:" + str(self.get_http_port()) + "/foo")
print(response)
@tornado.testing.gen_test(timeout=30)
async def test_fail(self):
response = await IOLoop.current().run_in_executor(None,"http://192.168.2.1:" + str(self.get_http_port()) + "/foo")
print(response)
第一个测试通过,而第二个测试失败
_____________________________________________________________ MyTest.test_fail _____________________________________________________________
self = <urllib3.connection.HTTPConnection object at 0x7fea40367e50>
def _new_conn(self):
"""Establish a socket connection and set nodelay settings on it.
:return: New socket connection.
"""
extra_kw = {}
if self.source_address:
extra_kw["source_address"] = self.source_address
if self.socket_options:
extra_kw["socket_options"] = self.socket_options
try:
conn = connection.create_connection(
> (self._dns_host,self.port),self.timeout,**extra_kw
)
../.virtualenvs/creative-preview/lib/python3.7/site-packages/urllib3/connection.py:170:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
address = ('192.168.2.1',41809),timeout = None,source_address = None,socket_options = [(6,1,1)]
def create_connection(
address,timeout=socket._GLOBAL_DEFAULT_TIMEOUT,source_address=None,socket_options=None,):
"""Connect to *address* and return the socket object.
Convenience function. Connect to *address* (a 2-tuple ``(host,port)``) and return the socket object. Passing the optional
*timeout* parameter will set the timeout on the socket instance
before attempting to connect. If no *timeout* is supplied,the
global default timeout setting returned by :func:`socket.getdefaulttimeout`
is used. If *source_address* is set it must be a tuple of (host,port)
for the socket to bind as a source address before making the connection.
An host of '' or port 0 tells the OS to use the default.
"""
host,port = address
if host.startswith("["):
host = host.strip("[]")
err = None
# Using the value from allowed_gai_family() in the context of getaddrinfo lets
# us select whether to work with IPv4 DNS records,IPv6 records,or both.
# The original create_connection function always returns all records.
family = allowed_gai_family()
try:
host.encode("idna")
except UnicodeError:
return six.raise_from(
LocationParseError(u"'%s',label empty or too long" % host),None
)
for res in socket.getaddrinfo(host,port,family,socket.SOCK_STREAM):
af,socktype,proto,canonname,sa = res
sock = None
try:
sock = socket.socket(af,proto)
# If provided,set socket level options before connecting.
_set_socket_options(sock,socket_options)
if timeout is not socket._GLOBAL_DEFAULT_TIMEOUT:
sock.settimeout(timeout)
if source_address:
sock.bind(source_address)
sock.connect(sa)
return sock
except socket.error as e:
err = e
if sock is not None:
sock.close()
sock = None
if err is not None:
> raise err
../.virtualenvs/creative-preview/lib/python3.7/site-packages/urllib3/util/connection.py:96:
...
During handling of the above exception,another exception occurred:
self = <my_test.MyTest testMethod=test_fail>
@tornado.testing.gen_test(timeout=30)
async def test_fail(self):
> response = await IOLoop.current().run_in_executor(None,"http://192.168.2.1:" + str(self.get_http_port()) + "/foo")
my_test.py:18:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/lib/python3.7/concurrent/futures/thread.py:57: in run
result = self.fn(*self.args,**self.kwargs)
../.virtualenvs/creative-preview/lib/python3.7/site-packages/requests/api.py:76: in get
return request('get',url,params=params,**kwargs)
../.virtualenvs/creative-preview/lib/python3.7/site-packages/requests/api.py:61: in request
return session.request(method=method,url=url,**kwargs)
../.virtualenvs/creative-preview/lib/python3.7/site-packages/requests/sessions.py:542: in request
resp = self.send(prep,**send_kwargs)
../.virtualenvs/creative-preview/lib/python3.7/site-packages/requests/sessions.py:655: in send
r = adapter.send(request,**kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <requests.adapters.HTTPAdapter object at 0x7fea4034dbd0>,request = <PreparedRequest [GET]>,stream = False
timeout = Timeout(connect=None,read=None,total=None),verify = True,cert = None,proxies = OrderedDict()
def send(self,request,stream=False,timeout=None,verify=True,cert=None,proxies=None):
"""Sends PreparedRequest object. Returns Response object.
:param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
:param stream: (optional) Whether to stream the request content.
:param timeout: (optional) How long to wait for the server to send
data before giving up,as a float,or a :ref:`(connect timeout,read timeout) <timeouts>` tuple.
:type timeout: float or tuple or urllib3 Timeout object
:param verify: (optional) Either a boolean,in which case it controls whether
we verify the server's TLS certificate,or a string,in which case it
must be a path to a CA bundle to use
:param cert: (optional) Any user-provided SSL certificate to be trusted.
:param proxies: (optional) The proxies dictionary to apply to the request.
:rtype: requests.Response
"""
try:
conn = self.get_connection(request.url,proxies)
except LocationValueError as e:
raise InvalidURL(e,request=request)
self.cert_verify(conn,request.url,verify,cert)
url = self.request_url(request,proxies)
self.add_headers(request,stream=stream,timeout=timeout,verify=verify,cert=cert,proxies=proxies)
chunked = not (request.body is None or 'Content-Length' in request.headers)
if isinstance(timeout,tuple):
try:
connect,read = timeout
timeout = TimeoutSauce(connect=connect,read=read)
except ValueError as e:
# this may raise a string formatting error.
err = ("Invalid timeout {}. Pass a (connect,read) "
"timeout tuple,or a single float to set "
"both timeouts to the same value".format(timeout))
raise ValueError(err)
elif isinstance(timeout,TimeoutSauce):
pass
else:
timeout = TimeoutSauce(connect=timeout,read=timeout)
try:
if not chunked:
resp = conn.urlopen(
method=request.method,body=request.body,headers=request.headers,redirect=False,assert_same_host=False,preload_content=False,decode_content=False,retries=self.max_retries,timeout=timeout
)
# Send the request.
else:
if hasattr(conn,'proxy_pool'):
conn = conn.proxy_pool
low_conn = conn._get_conn(timeout=DEFAULT_POOL_TIMEOUT)
try:
low_conn.putrequest(request.method,skip_accept_encoding=True)
for header,value in request.headers.items():
low_conn.putheader(header,value)
low_conn.endheaders()
for i in request.body:
low_conn.send(hex(len(i))[2:].encode('utf-8'))
low_conn.send(b'\r\n')
low_conn.send(i)
low_conn.send(b'\r\n')
low_conn.send(b'0\r\n\r\n')
# Receive the response from the server
try:
# For Python 2.7,use buffering of HTTP responses
r = low_conn.getresponse(buffering=True)
except TypeError:
# For compatibility with Python 3.3+
r = low_conn.getresponse()
resp = HTTPResponse.from_httplib(
r,pool=conn,connection=low_conn,decode_content=False
)
except:
# If we hit any problems here,clean up the connection.
# Then,reraise so that we can handle the actual exception.
low_conn.close()
raise
except (ProtocolError,socket.error) as err:
raise ConnectionError(err,request=request)
except MaxRetryError as e:
if isinstance(e.reason,ConnectTimeoutError):
# TODO: Remove this in 3.0.0: see #2811
if not isinstance(e.reason,NewConnectionError):
raise ConnectTimeout(e,request=request)
if isinstance(e.reason,ResponseError):
raise RetryError(e,_ProxyError):
raise ProxyError(e,_SSLError):
# This branch is for urllib3 v1.22 and later.
raise SSLError(e,request=request)
> raise ConnectionError(e,request=request)
E requests.exceptions.ConnectionError: HTTPConnectionPool(host='192.168.2.1',port=41809): Max retries exceeded with url: /foo (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7fea40367e50>: Failed to establish a new connection: [Errno 111] Connection refused'))
../.virtualenvs/creative-preview/lib/python3.7/site-packages/requests/adapters.py:516: ConnectionError
==================================================== 1 failed,1 passed in 0.22 seconds ==================================================
192.168.2.1
也是本地主机(通过 docker0
接口)。奇怪的是,如果我运行一个简单的 http 服务器 python -m http.server
,那么 curl 127.0.0.1:8000
和 curl 192.168.2.1:8000
两者 都可以工作,所以它似乎与 docker 无关问题。所以我真的不知道发生了什么
解决方法
你能试试 curl -v 192.168.2.1:8000 (verbose) 并检查输出吗? 也许你被重定向到 localhost 而它没有发生在你的代码中。
你的应用监听主机是什么?本地主机还是 0.0.0.0?
如果您希望能够从本地计算机进行连接,您需要确保您正在收听 0.0.0.0
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。