英文:
502 Bad Gateway: net/http GET failed with IPSec Tunnel
问题
在Windows上使用net/http
包通过IPSec隧道(VPN)进行远程GET请求时,GET请求失败,响应代码为502 Bad Gateway。然而,使用相同的headers、uri和method通过curl发送的请求却能正常工作。以下是Go源代码的样子:
var req *http.Request
req, err = http.NewRequest('GET', *uri, reader)
if nil != err {
level.Warn(log).Log('msg', '无法创建请求', 'err', err, 'uri', uri)
return nil, err
}
if nil != req.Body {
defer req.Body.Close()
}
for h, v := range opts.Headers {
req.Header.Add(h, *v)
}
client := http.Client{}
if nil != err {
return nil, err
}
res, err := client.Do(req)
if nil != err {
level.Warn(log).Log('msg', '无法发送请求', 'err', err, 'uri', uri)
return nil, err
}
defer res.Body.Close()
buf, err := io.ReadAll(res.Body)
if nil != err {
level.Warn(log).Log('msg', '无法读取响应', 'err', err, 'uri', uri, 'status', res.Status, 'status_code', res.StatusCode)
return nil, err
}
在捕获和分析流量后,我发现通过curl发送的请求可以在VPN接口上正常捕获,但通过go(net/http)发送的GET请求却丢失了。
然后我猜测可能是框架选择了错误的接口来发送数据包。
因此,我尝试找到适当的本地网络接口,并指定其LocalAddr来发送我的GET请求,代码如下:
func Client(u string) (*http.Client, error) {
uri, err := url.Parse(u)
if nil != err {
return nil, err
}
host := uri.Host
port := uri.Port()
if Empty == port {
if uri.Scheme == 'http' {
host = host + ':80'
} else if uri.Scheme == 'https' {
host = host + ':443'
}
}
conn, err := net.Dial('tcp', host)
if nil != err {
return nil, err
}
addr := conn.LocalAddr().(*net.TCPAddr)
// **确保使用随机端口作为本地端口**
addr.Port = 0
dialer := &net.Dialer{LocalAddr: addr}
dialContext := func(ctx context.Context, network, addr string) (net.Conn, error) {
conn, err := dialer.Dial(network, addr)
return conn, err
}
transport := &http.Transport{DialContext: dialContext}
client := &http.Client{
Transport: transport,
}
return client, nil
}
将client := &http.Client{}
替换为client, err := Client(uri)
后,GET请求最终可以正常工作。
然后,我的问题是为什么Golang不会自动选择适当的本地网络接口来发送请求?
英文:
When making remote GET
requests with net/http
package through IPSec Tunnel(VPN)
on windows, GET
request failed with response code 502 Bad Gateway
. However request with same headers
, uri
, method
sent by curl
works greatly. The go
source code looks like:
var req *http.Request
req, err = http.NewRequest('GET', *uri, reader)
if nil != err {
level.Warn(log).Log("msg", "Unable to create request", "err", err, "uri", uri)
return nil, err
}
if nil != req.Body {
defer req.Body.Close()
}
for h, v := range opts.Headers {
req.Header.Add(h, *v)
}
client := http.Client{}
if nil != err {
return nil, err
}
res, err := client.Do(req)
if nil != err {
level.Warn(log).Log("msg", "Unable to send request", "err", err, "uri", uri)
return nil, err
}
defer res.Body.Close()
buf, err := io.ReadAll(res.Body)
if nil != err {
level.Warn(log).Log("msg", "Unable to read response", "err", err, "uri", uri, "status", res.Status, "status_code", res.StatusCode)
return nil, err
}
After capturing and analysising the traffic, I found the request sent by curl
can be captured normally on VPN Interface
but GET
request sent from go(net/http)
lost.
Then I guess it probably because the framework seleted wrong interface to send the packet.
So I tried to find out proper local network interface and specify its LocalAddr
to send my GET
request as following:
func Client(u string) (*http.Client, error) {
uri, err := url.Parse(u)
if nil != err {
return nil, err
}
host := uri.Host
port := uri.Port()
if Empty == port {
if uri.Scheme == "http" {
host = host + ":80"
} else if uri.Scheme == "https" {
host = host + ":443"
}
}
conn, err := net.Dial("tcp", host)
if nil != err {
return nil, err
}
addr := conn.LocalAddr().(*net.TCPAddr)
// **make sure using random port as local port**
addr.Port = 0
dialer := &net.Dialer{LocalAddr: addr}
dialContext := func(ctx context.Context, network, addr string) (net.Conn, error) {
conn, err := dialer.Dial(network, addr)
return conn, err
}
transport := &http.Transport{DialContext: dialContext}
client := &http.Client{
Transport: transport,
}
return client, nil
}
And after repacing client
with Client
function, GET
request final works.
client := &http.Client{}
=> client, err := Client(uri)
Then my question is why golang
doesn't select proper local network interface to send request automatically?
答案1
得分: 0
在调试net.dial#DialContext
之后,我发现在Visual Studio Code
的设置中,地址已经被更改为我的代理地址。而我的代理服务器将无法处理我的应用程序请求。
当我移除代理设置时,net.dial
按预期工作。
问题所在
我正在使用vscode与TypeScript/Java/Golang...
一起工作,这是我在vscode
IDE中首次遇到代理问题。换句话说,我从未想过IDE
代理会对其构建的工作产生影响。因为扩展或IDE本身使用这个代理设置是合理的,但我的golang
项目调试也使用了它,这真的让我很困惑。
英文:
After debugging the net.dial#DialContext
, I found the address has been changed to my proxy address in Visual Studio Code
settings. And my proxy server won't be able to handle my application requests.
When I removed the proxy setting, net.dial
works as expected.
What matters
I'm using vscode to work with TypeScript/Java/Golang...
and this is the first time I encounter a proxy issue on Developing Application
in vscode
IDE. In other words, I never thought the IDE
proxy will work on the work it builds. Since extensions or IDE itself use this proxy settings is reasonable but my golang
project debugging use it too that really confused me a lot.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论