【待解決】記一次域名大小寫導致的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
很神奇!!!
天道酬勤