【待解决】记一次域名大小写导致的API调用失败问题

在一次项目应用过程中,需要调用另一个组件的API,在url中将其域名配置为了大写,并在本地的/etc/hosts配置了对应的IP和域名的映射关系,但是在项目运行过程中,调用接口的时候仍然出现了错误:

Failed to establish a new connection: [Errno -2] No address found

下面分析下在项目中调用API的代码:

API请求过程代码分析:

依然以requests.Session.request为例。

在request方法中,会调用self.send方法进行请求发送:

 在Session.send方法中,会先根据url生成一个adapter对象,然后调用adapter对象的send方法发送请求:

 adapter为requests/adapters.py中HTTPAdapter类的对象,其send方法中,则会调用self.get_connection获取一个conn对象,并调用conn的urlopen方法进行API调用:

 在self.get_connection方法中,先调用 select_proxy获取代理,由于我在发送请求的时候没使用代理,所以proxy为None;接着调用self.poolmanager的connection_from_url方法获取url的连接

 self.poolmanager为HTTPAdapter初始化的时候就配置好了:

 PoolManager为导入的requests.packages.urllib3.poolmanager中的类:

 

 在PoolManager中的connection_from_url方法里,返回的是调用self.connection_from_host的值:

 而在connection_from_host中,又调用了connection_from_context;在connection_from_context中,又调用了connection_from_pool_key

 在connection_from_pool_key中,调用了self._new_pool方法返回一个pool对象:

 在_new_pool中,则是根据scheme获取对应的pool_cls,再对其进行初始化对象:

 而pool_classes_by_scheme定义为:

 HTTPConnectionPool又是从requests.connectionpool中导入进来的:

 所以最终,conn就是一个requests.packages.urllib3.connectionpool.py中的HTTPConnectionPool对象。

下面则是对conn.urlopen方法的调用:

再来看看urlopen方法的定义。
在requests.packages.urllib3.connectionpool.py中,HTTPConnectionPool的urlopen方法定义为:

其中会先获取一个conn对象,再调用self._make_request方法发送请求。

在self._get_conn中,是从self.pool中获取block对应的conn对象,如果没有,则调用self._new_conn生成一个新的conn对象:

 在HTTPConnectionPool中,_new_conn定义为:

 而HTTPConnectionPool中,已经定义了ConnectionCls属性:

 HTTPConnection是被导入进来的一个类:

 所以,这里返回的就是一个requests/packages/urllib3/connection.py中的HTTPConnection对象

在_make_request中,chunked为默认的False,则调用conn.request方法:

而在requests/packages/urllib3/connection.py中,HTTPConnection为导入进来的模块:

from .packages.six.moves.http_client import HTTPConnection as _HTTPConnection

在requests/packages/urllib3/packages/six.py中,

 

 通过MoveModule将httplib模块命名为http_client(对于python3,则是将httplib命名为http.client)

所以最终调用的是httplib模块的request方法:

 在httplib中,_send_request定义如下,会调用self.endheaders方法:

 在endheaders方法中,定义如下,会调用self._send_output方法发送数据:

 httplib中,_send_output方法定义如下,其中会调用self.send方法:

 httplib中send方法定义为:

 self.sock初始为None,self.auto_open初始为1:

 所以会调用self.connect方法建立连接。

回到requests/packages/urllib3/connection.py中的HTTPConnection类中,connect方法定义为:

 其中,_new_conn定义为:

 这里会调用requests/packages/urllib3/util/connection.py中的create_connection方法:

在create_connection中,会调用socket的getaddrinfo获取host对应的IP信息:

如果本地域名解析中配置了对应的host的映射关系,如:

  • 只配置大写:
100.73.54.21 IRONIC

则可以解析出对应的IP,如果没有配置映射关系,则解析失败:

  •  只配置小写
100.73.54.21 ironic

则可以解析出对应的IP,如果没有配置映射关系,则解析失败:

  •  大小写都配置:
100.73.54.21 IRONIC ironic

则都能解析:

以上是在项目运行过程发现的问题,但是我直接用python的IDLE的时候,如果只配置某一个,则仍然可以解析:

  • 只配置大写
100.73.54.21 IRONIC

  •  只配置小写
100.73.54.21 ironic

很神奇!!!

天道酬勤
原文地址:https://www.cnblogs.com/wangwei1/p/15785434.html