Golang Http 庫指定 dns 伺服器進行解析
GolangHttp 庫指定 dns 伺服器進行解析
前言
個人專案有個需求某個功能傳送 http 請求的時候域名解析時走的是後臺設定 dns 伺服器。網上搜了下大多數都是使用第三方包並且沒有融合到 http Client 中的例子.想了想 Go 底層肯定有實現了相關的功能的程式碼
開始行動
最開始的想法很簡單使用第三方包定時解析域名放到 hosts 中,解決是解決了但是我這顆探究的心想讓我深入探索下
通常的 http 請求最終執行的都是 http.Client.Do 這個方法。so 第一步就是翻閱這個方法的原始碼。
呼叫 send
來獲取 resp。獲取 resp 肯定是要傳送請求的?。
if resp, didTimeout, err = c.send(req, deadline); err != nil {
// c.send() always closes req.Body
reqBodyClosed = true
if !deadline.IsZero() && didTimeout() {
err = &httpError{
// TODO: early in cycle: s/Client.Timeout exceeded/timeout or context cancellation/
err: err.Error() + " (Client.Timeout exceeded while awaiting headers)",
timeout: true,
}
}
return nil, uerr(err)
}
進入方法內部發現他呼叫了一個同名的函式
resp, didTimeout, err = send(req, c.transport(), deadline)
if err != nil {
return nil, didTimeout, err
}
追蹤下去發現 resp 返回自引數中 rt 的 RoundTrip 方法
resp, err = rt.RoundTrip(req)
if err != nil {
stopTimer()
if resp != nil {
log.Printf("RoundTripper returned a response & error; ignoring response")
}
c.transport() 的程式碼如下
func (c *Client) transport() RoundTripper {
if c.Transport != nil {
return c.Transport
}
return DefaultTransport
}
根據上面的方法我們找到 DefaultTransport
var DefaultTransport RoundTripper = &Transport{
Proxy: ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
很明顯 DefaultTransport 是 Transport 的預設實現。進入Transport
搜尋 RoundTrip
方法。RoundTrip
沒找到但是找到了 roundTrip
並且這個函式備註上還寫著 roundTrip implements a RoundTripper over HTTP.
(wtf 小寫的也算實現嗎?)
進入roundTrip
方法後由於呼叫層次太多我直接寫出重要的
Transport
中並沒有解析 dns 的相關程式碼 而是呼叫Transport.DialContext
建立 tcp 連結。
所以這裡的重點要轉入 net.Dialer.DialContext
方法,翻閱DialContext
原始碼發現 dns 解析是在這裡呼叫的
addrs, err := d.resolver().resolveAddrList(resolveCtx, "dial", network, address, d.LocalAddr)
if err != nil {
return nil, &OpError{Op: "dial", Net: network, Source: nil, Addr: nil, Err: err}
}
點開 resolver 函式
func (d *Dialer) resolver() *Resolver {
if d.Resolver != nil {
return d.Resolver
}
return DefaultResolver
}
發現他跟 transport 方法沒啥差別預設情況下返回 DefaultResolver
,DefaultResolver
是 Resolver
的預設實現。
由於 resolveAddrList
呼叫的層數太多了我就直說重點
Go 並沒有提供指定 Dns 解析伺服器的函式。但是我們可以通過配置Resolver
的 Dial 函式來實現類似的功能
r.Dial = func(ctx context.Context, network, address string) (net.Conn, error) {
d := net.Dialer{}
address = "8.8.8.8:53"
return d.DialContext(ctx, network, address)
}
addrs,err := r.LookupHost(context.Background(), "steamcommunity.com")
if err != nil{
panic(err)
}
fmt.Println(addrs)
這相當於替換系統原來 dns 伺服器地址換成我們的
結合到 http.Client
根據上面的那個內容照葫蘆畫瓢反向定義一波就行了 先定義 Transport
var SpecifiDnsServerTransport http.RoundTripper = &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
Resolver: &net.Resolver{PreferGo: true, Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
d := net.Dialer{}
address = "8.8.8.8:53"
return d.DialContext(ctx, network, address)
}},
}).DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
在定義 http.Client
var SpecifiDnsServerClient = http.Client{Transport: SpecifiDnsServerTransport}
然後就是你自己的業務程式碼了
最後
其實如果業務程式碼中需要單純的獲取域名解析 Resolver
下已經定義好了一堆方法 net
也對Resolver
進行函式封裝了
addr, err := net.LookupHost("www.baidu.com")
if err != nil {
panic(err)
}
fmt.Println(addr)
以上程式碼即可獲取 www.baidu.com 的 A 跟 AAAA 指向
- 加微信實戰群請加微信(註明:實戰群):gocnio
相關文章
- 國內DNS最快的伺服器 解析最快的dnsDNS伺服器
- DNS解析常見問題:什麼是主DNS伺服器和輔助DNS伺服器?DNS伺服器
- [HTTP 系列] 第 1 篇 —— 從 TCP/UDP 到 DNS 解析HTTPTCPUDPDNS
- 主從DNS域名解析伺服器DNS伺服器
- Golang如何實現HTTP代理伺服器GolangHTTP伺服器
- 使用cJSON庫對JSON格式進行解析JSON
- 使用了lua-resty-http庫進行 爬蟲RESTHTTP爬蟲
- 在Linux中,DNS進行域名解析的過程是什麼?LinuxDNS
- linux下安裝dns域名解析伺服器LinuxDNS伺服器
- golang常用庫:配置檔案解析庫-viper使用Golang
- 什麼是DNS解析?如何提升DNS解析安全?DNS
- DNS解析流程DNS
- DNS解析原理DNS
- 雲伺服器如何解決DNS解析錯誤故障伺服器DNS
- 主流域名解析庫曝重大DNS投毒漏洞,如何有效應對DNS投毒?DNS
- 指定特定的jdk進行安裝JDK
- 第3步: 域名解析伺服器的過程(DNS)伺服器DNS
- 【知識分享】dns解析伺服器的幾個步驟DNS伺服器
- 透過dns進行檔案下載DNS
- 利用DNS日誌進行MySQL盲注DNSMySql
- DNS域名解析DNS
- 詳解 DNS 解析DNS
- Linux給特定程式單獨指定DNSLinuxDNS
- 如何判斷DNS解析故障?如何解決DNS解析錯誤?DNS
- DNS解析為什麼不生效?DNS解析不生效原因分析DNS
- postman進行http介面測試PostmanHTTP
- 使用 $fetch 進行 HTTP 請求HTTP
- dns伺服器DNS伺服器
- C++ 用libcurl庫進行http通訊網路程式設計C++HTTP程式設計
- http協議獲取實時天氣並對包體進行json解析HTTP協議JSON
- DNS分層結構及DNS解析流程DNS
- 雲解析DNS有必要買嗎?雲解析DNS有什麼用?DNS
- 【中科三方】什麼是雲解析DNS?雲解析DNS有必要購買嗎?如何購買雲解析DNS?DNS
- DNS隧道技術解析DNS
- golang http 中介軟體GolangHTTP
- 雲解析DNS如何實現智慧解析?DNS
- 解析最快的dns 最快最穩定的dnsDNS
- golang bufio解析Golang