1. 程式人生 > 其它 >【待解決】記一次域名大小寫導致的API呼叫失敗問題

【待解決】記一次域名大小寫導致的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

很神奇!!!

天道酬勤