How to bind an http.Client in Go to an IP Address

huangapple go评论85阅读模式
英文:

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(&quot;ip&quot;, &quot;&lt;my local address&gt;&quot;)
if err != nil {
  panic(err)
}

// You also need to do this to make it work and not give you a 
// &quot;mismatched local address type ip&quot;
// This will make the ResolveIPAddr a TCPAddr without needing to 
// say what SRC port number to use.
localTCPAddr := net.TCPAddr{
	IP: localAddr.IP,
}


webclient := &amp;http.Client{
	Transport: &amp;http.Transport{
		Proxy: http.ProxyFromEnvironment,
		DialContext: (&amp;net.Dialer{
			LocalAddr: &amp;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 (
	&quot;fmt&quot;
	&quot;io/ioutil&quot;
	&quot;net&quot;
	&quot;net/http&quot;
	&quot;time&quot;
)

func main() {
	localAddr, err := net.ResolveIPAddr(&quot;ip&quot;, &quot;10.128.64.219&quot;)
	if err != nil {
		panic(err)
	}

	localTCPAddr := net.TCPAddr{
		IP: localAddr.IP,
	}

	d := net.Dialer{
		LocalAddr: &amp;localTCPAddr,
		Timeout:   30 * time.Second,
		KeepAlive: 30 * time.Second,
	}

	tr := &amp;http.Transport{
		Proxy:               http.ProxyFromEnvironment,
		Dial:                d.Dial,
		TLSHandshakeTimeout: 10 * time.Second,
	}

	webclient := &amp;http.Client{Transport: tr}

	// Use NewRequest so we can change the UserAgent string in the header
	req, err := http.NewRequest(&quot;GET&quot;, &quot;http://www.google.com:80&quot;, nil)
	if err != nil {
		panic(err)
	}

	res, err := webclient.Do(req)
	if err != nil {
		panic(err)
	}

	fmt.Println(&quot;DEBUG&quot;, res)
	defer res.Body.Close()

	content, err := ioutil.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	fmt.Printf(&quot;%s&quot;, string(content))
}

huangapple
  • 本文由 发表于 2015年11月18日 06:46:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/33768557.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定