douwei1930 2015-02-06 23:16
浏览 521

Golang HTTP发布错误:连接被拒绝

I am trying to send a post request to localhost on port 8080 where a PHP app is running.

Curl work fine:

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

But in Go I get the following error:

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

Here is the code:

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")

I monitored http traffic with httpry and i found out that no http request is generated but there are some packages:

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

Some more facts:

  • My OS is Linux
  • I use the PHP's built-in web server. The servers was started with this command:

    php -S localhost:8080

  • 写回答

1条回答 默认 最新

  • douwen3127 2015-07-10 01:35
    关注

    This issue appears to be resolved in Go 1.6. For reference, the original answer follows.


    The problem here is that Go's net.Dialer only makes IPv4 connections by default (this appears to be a bug), but your PHP server is listening only on IPv6.

    When you run php -S localhost:8080 it is doing the (mostly) right thing and binding to the IPv6 address ::1. It does not bind to IPv4.

    This isn't a problem for most software, which knows to attempt IPv6 connections first, but what happens when you call http.PostForm() is that net.http uses its DefaultTransport, which by default uses a net.Dialer Dial() to make outgoing connections. Dial() attempts to resolve the address, and then we wind up deep in the resolver in src/net/ipsock.go, where we find out that the Go developers intentionally screwed it up while trying to work around something else:

            // 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.
    

    This is obviously a problem, since IPv6 is supposed to be the default and preferred protocol. Linux and PHP are behaving correctly, while Go itself is not.

    The comment above was found in the 1.4 branch. In the master branch this has been completely rewritten, but in the new code it's non-obvious whether an IPv6 or IPv4 address will be preferred. It may well be nondeterministic; I didn't spend too much time looking at it. Based on the issues I found on GitHub, (see below) it is unlikely to be actually fixed.

    In the meantime you can work around this bug by either having Go connect to ::1 or having PHP bind to 127.0.0.1. You could also construct your own RoundTripper with correct behavior, but that's probably too much work, unless you're actually having problems reaching IPv6-enabled services (and eventually we all will, so this really needs to be fixed).

    Some relevant Go issues include:

    And several other older issues that are no longer relevant since the code has long since been rewritten...

    评论

报告相同问题?

悬赏问题

  • ¥20 求个正点原子stm32f407开发版的贪吃蛇游戏
  • ¥15 正弦信号发生器串并联电路电阻无法保持同步怎么办
  • ¥15 划分vlan后,链路不通了?
  • ¥20 求各位懂行的人,注册表能不能看到usb使用得具体信息,干了什么,传输了什么数据
  • ¥15 Vue3 大型图片数据拖动排序
  • ¥15 Centos / PETGEM
  • ¥15 划分vlan后不通了
  • ¥20 用雷电模拟器安装百达屋apk一直闪退
  • ¥15 算能科技20240506咨询(拒绝大模型回答)
  • ¥15 自适应 AR 模型 参数估计Matlab程序