简体   繁体   English

如何捕获提供 HTTP 响应的服务器的 IP 地址

[英]How to capture IP address of server providing HTTP response

Using Go's default HTTP client , I am unable to directly determine the IP address of the server that processed the request.使用 Go 的默认 HTTP 客户端,我无法直接确定处理请求的服务器的 IP 地址。 For instance, when requesting example.com , what is the IP address that example.com resolved to at the time of the request?例如,当请求example.com ,什么是IP地址example.com在要求的时间分辨什么?

import "net/http"

resp, err := http.Get("http://example.com/")

The resp object contains the resp.RemoteAddr property, but as detailed below it is not utilized during client operations. resp对象包含resp.RemoteAddr属性,但如下详述,在客户端操作期间不使用它。

 // RemoteAddr allows HTTP servers and other software to record
 // the network address that sent the request, usually for
 // logging. This field is not filled in by ReadRequest and
 // has no defined format. The HTTP server in this package
 // sets RemoteAddr to an "IP:port" address before invoking a
 // handler.
 // This field is ignored by the HTTP client.
 RemoteAddr string

Is there a straightforward way to accomplish this?有没有一种直接的方法来实现这一点? My initial thought would be to:我最初的想法是:

  1. Initiate a DNS lookup to remote domain启动对远程域的 DNS 查找
  2. Create new http transport using returned A/AAAA records使用返回的 A/AAAA 记录创建新的http传输
  3. Make the request提出请求
  4. Set the RemoteAddr property on the response object在响应对象上设置RemoteAddr属性

Is there a better way?有更好的方法吗?


UPDATED - to use @flimzy's suggestion.更新 - 使用@flimzy 的建议。 This method stores the remote IP:PORT into the request.RemoteAddr property.此方法将远程 IP:PORT 存储到request.RemoteAddr属性中。 I've also added support for multiple redirects so that each subsequent request has its RemoteAddr populated.我还添加了对多个重定向的支持,以便每个后续请求都填充其RemoteAddr

request, _ := http.NewRequest("GET", "http://www.google.com", nil)
client := &http.Client{
    Transport:&http.Transport{
        DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
            conn, err := net.Dial(network, addr)
            request.RemoteAddr = conn.RemoteAddr().String()
            return conn, err
        },
    },
    CheckRedirect: func(req *http.Request, via []*http.Request) error {
        request = req
        return nil
    },
}
resp, _ := client.Do(request)

As far as I can tell, the only way to accomplish this with the standard library is with a custom http.Transport that records the remote IP address, for example in the DialContext function.据我所知,使用标准库完成此操作的唯一方法是使用自定义http.Transport记录远程 IP 地址,例如在DialContext函数中。

client := &http.Client{
    Transport: &http.Transport{
        DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
            conn, err := net.Dial(network, addr)
            fmt.Printf("Remote IP: %s\n", conn.RemoteAddr())
            return conn, err
        },
    },
}
resp, _ := client.Get("http://www.google.com")

Tying the connection IP to the response is left as an exercise for the reader.将连接 IP 绑定到响应留给读者作为练习。

you also can build a request with trace:您还可以使用跟踪构建请求:

request = request.WithContext(httptrace.WithClientTrace(request.Context(), &httptrace.ClientTrace{
        GotConn: func(connInfo httptrace.GotConnInfo) {
            fmt.Printf("target ip:%+v\n", connInfo.Conn.RemoteAddr().String())
        },
    }))
response, _:= client.Do(request)

httptrace form https://golang.org/pkg/net/http/httptrace/ httptrace 表单https://golang.org/pkg/net/http/httptrace/

req, err := http.NewRequest(method, url, strings.NewReader(body))
    trace := &httptrace.ClientTrace{
        GotConn: func(connInfo httptrace.GotConnInfo) {
            fmt.Printf("Got Conn: %+v\n", connInfo)
        },
        DNSDone: func(dnsInfo httptrace.DNSDoneInfo) {
            fmt.Printf("DNS Info: %+v\n", dnsInfo)
        },
    }
req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM