Golang HTTP Post 错误:连接被拒绝

7

我正在尝试向运行PHP应用程序的本地主机端口8080发送POST请求。

Curl工作正常:

curl --data "key=asdf" http://localhost:8080/

但是在Go中我会遇到以下错误:

Post http://localhost:8080: dial tcp 127.0.0.1:8080: connection refused

这里是代码:
func submitForm(value string){
    resp, err := http.PostForm("http://localhost:8080", url.Values{"key": {value}})
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()
    _, err = ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("status = ",resp.Status)
}
submitForm("asdf")

我使用httpry监控了http流量,发现没有生成任何http请求,但仍有一些数据包:

4 packets received, 0 packets dropped, 0 http packets parsed

更多的事实:

  • 我的操作系统是Linux
  • 我使用PHP内置的Web服务器。 服务器是使用以下命令启动的:

    php -S localhost:8080


这段代码对我来说运行良好。你如何调用 submitForm 函数以及如何启动 PHP 服务器?服务器和这段 Go 代码在同一台机器上运行,是吗? - Ethan
我这样调用它:submitForm("asdf") 服务器是这样在同一台机器上启动的:php -S localhost:8080 你认为这是 PHP 的(而不是 Go 的)问题吗? - Jaxx
可能。PHP的版本是什么?比较一下使用curl和go发出的HTTP请求,看看PHP服务器是否在寻找头部方面存在差异可能会很有趣。 - Ethan
PHP 5.6.4如何查看HTTP请求?在PHP中打印$ _POST无法工作,因为请求被拒绝。 - Jaxx
对,我想你可能可以打印go请求,但是你不能因为你使用PostForm。而且我不确定如何使php服务器更加详细。在go中,Get或Post函数是否有效?你是否尝试使用低级别的go函数构建请求,就像这里解释的一样http://golang.org/pkg/net/http/? - Ethan
显示剩余4条评论
1个回答

11
这个问题似乎在Go 1.6中已经解决。以下是原始答案。

这里的问题是,Go的net.Dialer默认只建立IPv4连接(这似乎是一个错误),但是你的PHP服务器仅监听IPv6。

当你运行php -S localhost:8080时,它会做(大多数)正确的事情,并绑定到IPv6地址::1。它不绑定IPv4。

对于大多数软件来说,这不是问题,它们知道首先尝试IPv6连接,但是当你调用http.PostForm()时,net.http使用其DefaultTransport,该传输默认使用net.Dialer Dial()进行出站连接。Dial()尝试解析地址,然后我们深入src/net/ipsock.go中的解析器,发现Go开发人员在试图解决其他问题时故意搞砸了它:

        // We'll take any IP address, but since the dialing
        // code does not yet try multiple addresses
        // effectively, prefer to use an IPv4 address if
        // possible. This is especially relevant if localhost
        // resolves to [ipv6-localhost, ipv4-localhost]. Too
        // much code assumes localhost == ipv4-localhost.

这显然是一个问题,因为IPv6应该是默认和首选的协议。Linux和PHP行为正确,而Go本身则没有。
上面的评论是在1.4分支中发现的。在主分支中,这已经被完全重写,但在新代码中,不明显哪个是首选的IPv6或IPv4地址。它可能是不确定的;我没有花太多时间去看它。根据我在GitHub上找到的问题(见下文),它不太可能真正得到修复。
同时,您可以通过让Go连接到 :: 1 或让PHP绑定到 127.0.0.1 来解决此错误。您还可以构建具有正确行为的自己的RoundTripper,但除非您实际上无法访问启用了IPv6的服务(我们最终都会这样做),否则这可能太麻烦了,因此需要解决此问题。
一些相关的Go问题包括:

还有一些旧问题,由于代码早已被重写,因此不再相关...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接