英文:
How to bind an http.Client in Go to an IP Address
问题
我有一台具有多个网络接口的客户机,如何在Go中将http.Client绑定到特定的网络接口或特定的源IP地址?
假设你有一些非常基本的http客户端代码,如下所示:
package main
import (
"net/http"
)
func main() {
webclient := &http.Client{}
req, _ := http.NewRequest("GET", "http://www.google.com", nil)
httpResponse, _ := webclient.Do(req)
defer httpResponse.Body.Close()
}
有没有办法绑定到特定的网络接口或IP地址?
英文:
I have a client machine with multiple NICs, how do I bind an http.Client in Go to a certain NIC or to a certain SRC IP Address?
Say you have some very basic http client code that looks like:
package main
import (
"net/http"
)
func main() {
webclient := &http.Client{}
req, _ := http.NewRequest("GET", "http://www.google.com", nil)
httpResponse, _ := webclient.Do(req)
defer httpResponse.Body.Close()
}
Is there a way to bind to a certain NIC or IP?
答案1
得分: 17
与这个问题类似,你需要设置http.Client.Transport
字段。将其设置为net.Transport
的实例可以让你指定要使用的net.Dialer
。然后,net.Dialer
允许你指定本地地址以进行连接。
示例代码:
localAddr, err := net.ResolveIPAddr("ip", "<我的本地地址>")
if err != nil {
panic(err)
}
// 为了使其正常工作并避免出现“mismatched local address type ip”错误,
// 需要执行以下操作。这将使ResolveIPAddr成为一个TCPAddr,而不需要指定要使用的SRC端口号。
localTCPAddr := net.TCPAddr{
IP: localAddr.IP,
}
webclient := &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
LocalAddr: &localTCPAddr,
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
},
}
以上是代码的翻译部分。
英文:
Similar to this question, you need to set the http.Client.Transport
field. Setting it to an instance of net.Transport
allows you to specify which net.Dialer
you want to use. net.Dialer
then allows you to specify the local address to make connections from.
Example:
localAddr, err := net.ResolveIPAddr("ip", "<my local address>")
if err != nil {
panic(err)
}
// You also need to do this to make it work and not give you a
// "mismatched local address type ip"
// This will make the ResolveIPAddr a TCPAddr without needing to
// say what SRC port number to use.
localTCPAddr := net.TCPAddr{
IP: localAddr.IP,
}
webclient := &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
LocalAddr: &localTCPAddr,
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
},
}
答案2
得分: 5
以下是一个完整的工作示例,其中包含了Tim的答案。我还将所有嵌套的部分拆分出来,以便更容易阅读和学习。
package main
import (
"fmt"
"io/ioutil"
"net"
"net/http"
"time"
)
func main() {
localAddr, err := net.ResolveIPAddr("ip", "10.128.64.219")
if err != nil {
panic(err)
}
localTCPAddr := net.TCPAddr{
IP: localAddr.IP,
}
d := net.Dialer{
LocalAddr: &localTCPAddr,
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}
tr := &http.Transport{
Proxy: http.ProxyFromEnvironment,
Dial: d.Dial,
TLSHandshakeTimeout: 10 * time.Second,
}
webclient := &http.Client{Transport: tr}
// 使用NewRequest可以更改标头中的UserAgent字符串
req, err := http.NewRequest("GET", "http://www.google.com:80", nil)
if err != nil {
panic(err)
}
res, err := webclient.Do(req)
if err != nil {
panic(err)
}
fmt.Println("DEBUG", res)
defer res.Body.Close()
content, err := ioutil.ReadAll(res.Body)
if err != nil {
panic(err)
}
fmt.Printf("%s", string(content))
}
希望对你有帮助!
英文:
Here is a fully working example that incorporates the answer from Tim. I also broke out all of the nested pieces to make it easier to read and learn from.
package main
import (
"fmt"
"io/ioutil"
"net"
"net/http"
"time"
)
func main() {
localAddr, err := net.ResolveIPAddr("ip", "10.128.64.219")
if err != nil {
panic(err)
}
localTCPAddr := net.TCPAddr{
IP: localAddr.IP,
}
d := net.Dialer{
LocalAddr: &localTCPAddr,
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}
tr := &http.Transport{
Proxy: http.ProxyFromEnvironment,
Dial: d.Dial,
TLSHandshakeTimeout: 10 * time.Second,
}
webclient := &http.Client{Transport: tr}
// Use NewRequest so we can change the UserAgent string in the header
req, err := http.NewRequest("GET", "http://www.google.com:80", nil)
if err != nil {
panic(err)
}
res, err := webclient.Do(req)
if err != nil {
panic(err)
}
fmt.Println("DEBUG", res)
defer res.Body.Close()
content, err := ioutil.ReadAll(res.Body)
if err != nil {
panic(err)
}
fmt.Printf("%s", string(content))
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论