如何设置HTTP请求使用的IP地址?

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

How to set which IP to use for a HTTP request?

问题

我不知道是否可能,因为标准库没有说明当前使用的地址:

http://golang.org/pkg/net/http/

resp, err := http.Get("http://example.com/")
if err != nil {
// 处理错误
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)

我想要做的是为该HTTP请求设置源地址,为什么呢?因为我不想使用我的主要IP地址进行这种操作...

英文:

I dont know if it's possible as the std lib does not state anything about the current address being used:

http://golang.org/pkg/net/http/

resp, err := http.Get("http://example.com/")
if err != nil {
	// handle error
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)

What I'm trying to do is set the source address for that http request, why? because I don't want to use my primary ip address for that kind of stuff...

答案1

得分: 26

你可以在客户端的传输中设置自定义的拨号器。

// 创建一个传输对象,类似于http.DefaultTransport,但指定了localAddr
transport := &http.Transport{
    Proxy: http.ProxyFromEnvironment,
    DialContext: (&net.Dialer{
        Timeout:   30 * time.Second,
        KeepAlive: 30 * time.Second,
        LocalAddr: localAddr,
        DualStack: true,
    }).DialContext,
    MaxIdleConns:          100,
    IdleConnTimeout:       90 * time.Second,
    TLSHandshakeTimeout:   10 * time.Second,
    ExpectContinueTimeout: 1 * time.Second,
}

client := &http.Client{
    Transport: transport,
}

以上代码示例展示了如何在客户端的传输中设置自定义的拨号器。你可以根据需要修改其中的参数。

英文:

You can set a custom Dialer in the Client's Transport.

// Create a transport like http.DefaultTransport, but with a specified localAddr
transport := &http.Transport{
	Proxy: http.ProxyFromEnvironment,
	DialContext: (&net.Dialer{
		Timeout:   30 * time.Second,
		KeepAlive: 30 * time.Second,
		LocalAddr: localAddr,
		DualStack: true,
	}).DialContext,
	MaxIdleConns:          100,
	IdleConnTimeout:       90 * time.Second,
	TLSHandshakeTimeout:   10 * time.Second,
	ExpectContinueTimeout: 1 * time.Second,
}

client := &http.Client{
    Transport: transport,
}

答案2

得分: 0

使用指定的IP设置自定义拨号器有时可以工作,但有时却无法正常工作,这很奇怪,因为curl却可以正常工作。
在检查了curl的源代码后,我找到了curl能够指定要使用的网络接口的原因:SO_BINDTODEVICE。不幸的是,这是一个Linux的特性。

所以与JimB的答案相比,我的方法有:

  • 优点:与curl一样稳定,与路由表无关
  • 缺点:只支持Linux。所以你可能需要了解更多关于构建标签的内容,以编写特定于平台的代码。
dialer := &net.Dialer{
	Control: func(network, address string, conn syscall.RawConn) error {
		var operr error
		if err := conn.Control(func(fd uintptr) {
			operr = unix.BindToDevice(int(fd), forceNetworkInterface)
		}); err != nil {
			return err
		}
		return operr
	},
}

client = http.Client{
	Transport: &http.Transport{
		DialContext: dialer.DialContext,
	},
}

此外,curl执行的SO_BINDTODEVICE与上述代码的行为类似。对于非Linux平台,或者当SO_BINDTODEVICE失败时,curl会像JimB的答案一样设置本地IP地址。因此,你可以先尝试我的代码,然后作为备选方案使用JimB的答案。

详细信息请参阅curl的源代码

英文:

Setting up a custom dialer with the specify IP works sometimes, but it is weird since sometimes it failed to work, while curl works normally.
After checking the source code of curl, I figured out why curl is able to specify what network interface to be used: SO_BINDTODEVICE. Unfortunately this is a Linux thing.

So compared to JimB's answer, my method has:

  • Pro: Behaves as stable as curl, which is irrelevant from routing tables
  • Con: Only support Linux. So you probably want to learn more about the build tags to write platform-specific code.
dialer := &net.Dialer{
	Control: func(network, address string, conn syscall.RawConn) error {
		var operr error
		if err := conn.Control(func(fd uintptr) {
			operr = unix.BindToDevice(int(fd), forceNetworkInterface)
		}); err != nil {
			return err
		}
		return operr
	},
}

client = http.Client{
	Transport = &http.Transport{
		DialContext: dialer.DialContext,
	},
}

In addition, curl performs SO_BINDTODEVICE which behaves like the above code. And for non-Linux platforms, or when SO_BINDTODEVICE fails, curl sets the local IP address just as JimB's answer does. So you can first try my code and then use JimB's answer as a fallback.

See the source code of curl for details.

huangapple
  • 本文由 发表于 2015年5月31日 07:44:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/30552447.html
匿名

发表评论

匿名网友

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

确定