英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论