golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
123.92k stars 17.65k forks source link

net/http: js-wasm in nodejs HTTP requests fail #69106

Open sekulicd opened 2 months ago

sekulicd commented 2 months ago

Go version

go version go1.22.0 darwin/amd64

Output of go env in your module/workspace:

GO111MODULE='on'
GOARCH='amd64'
GOBIN=''
GOCACHE='/Users/sekulicd/Library/Caches/go-build'
GOENV='/Users/sekulicd/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMODCACHE='/Users/sekulicd/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='darwin'
GOPATH='/Users/sekulicd/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/local/Cellar/go/1.22.0/libexec'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/Cellar/go/1.22.0/libexec/pkg/tool/darwin_amd64'
GOVCS=''
GOVERSION='go1.22.0'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='cc'
CXX='c++'
CGO_ENABLED='1'
GOMOD='/Users/sekulicd/go/src/tst/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/q2/t3b78q_d1d9br0p8q1zqd8nc0000gn/T/go-build1746037209=/tmp/go-build -gno-record-gcc-switches -fno-common'

What did you do?

I want to make HTTP request from Go WASM inside Node JS.

Here is sample main.go

//go:build js && wasm
// +build js,wasm

package main

import (
    "io/ioutil"
    "log"
    "net/http"
)

func main() {
    c := http.Client{
        Transport: http.DefaultTransport,
    }
    resp, err := c.Get("https://httpbin.org/anything")
    if err != nil {
        log.Fatal(err)
    }

    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatal(err)
    }

    log.Println(string(body))
}

When i try to execute WebAssembly with Node.js with cmd:

GOOS=js GOARCH=wasm go run -exec="$(go env GOROOT)/misc/wasm/go_js_wasm_exec" .

I get bellow error:

2024/08/28 14:11:49 Get "https://httpbin.org/anything": dial tcp: lookup httpbin.org on 192.168.17.142:53: write udp 127.0.0.1:4->192.168.17.142:53: write: Connection reset by peer

I understood that with this PR if i add js/wasm build tags that http.DefaultTransport will use RoundTripper with fetch options.

What did you see happen?

2024/08/28 14:11:49 Get "https://httpbin.org/anything": dial tcp: lookup httpbin.org on 192.168.17.142:53: write udp 127.0.0.1:4->192.168.17.142:53: write: Connection reset by peer

What did you expect to see?

Response similar to bellow:

{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"Accept-Encoding": "gzip, deflate, br, zstd",
"Accept-Language": "en-US,en;q=0.9,sr;q=0.8,hr;q=0.7,bs;q=0.6,sh;q=0.5",
"Host": "httpbin.org",
"Priority": "u=0, i",
"Sec-Ch-Ua": "\"Not)A;Brand\";v=\"99\", \"Google Chrome\";v=\"127\", \"Chromium\";v=\"127\"",
"Sec-Ch-Ua-Mobile": "?0",
"Sec-Ch-Ua-Platform": "\"macOS\"",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Sec-Fetch-User": "?1",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36",
"X-Amzn-Trace-Id": "Root=1-66cf14ab-0caaf43c6309fce12a8d7bc2"
},
"json": null,
"method": "GET",
"origin": "77.222.25.88",
"url": "https://httpbin.org/anything"
}
prattmic commented 2 months ago

cc @golang/wasm @golang/js @neild

gabyhelp commented 2 months ago

Related Issues and Documentation

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

Zxilly commented 2 months ago

With the following code

//go:build js && wasm

package main

import (
    "fmt"
    "io"
    "log"
    "net/http"
    "runtime"
    "syscall/js"
)

func main() {
    fmt.Println(runtime.GOOS)
    fmt.Println(runtime.GOARCH)

    var p = js.Global().Get("process").Get("version").String()
    fmt.Println(p)

    c := http.Client{
        Transport: http.DefaultTransport,
    }
    resp, err := c.Get("https://httpbin.org/anything")
    if err != nil {
        log.Fatal(err)
    }

    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        log.Fatal(err)
    }

    log.Println(string(body))
}

I got

PS T:\gotmp> go run main.go
js
wasm
v22.3.0
2024/08/30 00:34:06 {
  "args": {},
  "data": "",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Accept-Encoding": "br, gzip, deflate",
    "Accept-Language": "*",
    "Host": "httpbin.org",
    "Sec-Fetch-Mode": "cors",
    "User-Agent": "node",
    "X-Amzn-Trace-Id": "Root=1-66d0a2fe-548f0f4a397f75581a5b352b"
  },
  "json": null,
  "method": "GET",
  "origin": "20.63.141.121",
  "url": "https://httpbin.org/anything"
}

Can you share more information about the environment?

Zxilly commented 2 months ago

Can you check if this code is working correctly without using the js/wasm target?

sekulicd commented 2 months ago

Can you check if this code is working correctly without using the js/wasm target?

Yeah, i know its working with go run but not with mentioned node binary, my goal is to make http req from node js using go http pkg

Zxilly commented 2 months ago

Can you describe the Node.js version you use?

Zxilly commented 2 months ago

Note that when I use go run, the appropriate wasm wrapper is already present in the environment variable, so I am indeed running a wasm binary, as you can see from the runtime information printed.

sekulicd commented 2 months ago

Note that when I use go run, the appropriate wasm wrapper is already present in the environment variable, so I am indeed running a wasm binary, as you can see from the runtime information printed.

v21.7.3

Zxilly commented 2 months ago
PS T:\gotmp> $env:GOARCH="wasm"
PS T:\gotmp> $env:GOOS="js"
PS T:\gotmp> cat .\main.go
//go:build js && wasm

package main

import (
        "fmt"
        "io"
        "log"
        "net/http"
        "runtime"
        "syscall/js"
)

func main() {
        fmt.Println(runtime.GOOS)
        fmt.Println(runtime.GOARCH)

        var p = js.Global().Get("process").Get("version").String()
        fmt.Println(p)

        c := http.Client{
                Transport: http.DefaultTransport,
        }
        resp, err := c.Get("https://httpbin.org/anything")
        if err != nil {
                log.Fatal(err)
        }

        defer resp.Body.Close()

        body, err := io.ReadAll(resp.Body)
        if err != nil {
                log.Fatal(err)
        }

        log.Println(string(body))
}
PS T:\gotmp> node --version
v21.7.3
PS T:\gotmp> go version
go version go1.23.0 windows/amd64
PS T:\gotmp> go run main.go
js
wasm
v21.7.3
2024/09/03 22:36:21 {
  "args": {},
  "data": "",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Accept-Encoding": "br, gzip, deflate",
    "Accept-Language": "*",
    "Host": "httpbin.org",
    "Sec-Fetch-Mode": "cors",
    "User-Agent": "node",
    "X-Amzn-Trace-Id": "Root=1-66d71ee2-595ae3d765b1eb967f72c0e7"
  },
  "json": null,
  "method": "GET",
  "origin": "8.217.95.142",
  "url": "https://httpbin.org/anything"
}

I can't reproduce it with exactly same version on Windows. Can you try to reproduce it on Linux?

sekulicd commented 2 months ago

I can't reproduce it with exactly same version on Windows. Can you try to reproduce it on Linux?

I am running this on MacOS(12.7.6), i followed this tutorial, did u tried with cmd i used? : GOOS=js GOARCH=wasm go run -exec="$(go env GOROOT)/misc/wasm/go_js_wasm_exec" .

Zxilly commented 2 months ago

I can reproduce it on Linux

zxilly@Zxilly-s-PC:/mnt/t/gotmp$ GOOS=js GOARCH=wasm go run -exec="$(go env GOROOT)/misc/wasm/go_js_wasm_exec" .
js
wasm
v22.8.0
2024/09/04 17:39:14 Get "https://httpbin.org/anything": dial tcp: lookup httpbin.org on 127.0.0.53:53: write udp 127.0.0.1:4->127.0.0.53:53: write: Connection reset by peer
exit status 1

I'll dive into it.

Zxilly commented 2 months ago

related: https://github.com/golang/go/issues/57613 https://github.com/golang/go/issues/60011

gopherbot commented 2 months ago

Change https://go.dev/cl/611215 mentions this issue: net/http: only disable fetch in test