Golang中Webassembly报错:userCurrent未定义问题

Golang中Webassembly报错:userCurrent未定义问题 我正在尝试使用 WebAssembly。但在编译时遇到了一个错误:

GOOS=js GOARCH=wasm go build -o main.wasm  # github.com/lib/pq  ../../github.com/lib/pq/conn.go:321:13: undefined: userCurrent

有人知道这是什么问题以及如何解决吗?

12 回复

skillian:

我不认为它的目标是消除对Web服务器的需求。

如果我的理解正确,Web服务器是将wasm上传到客户端吗?那么SQL相关的操作是在哪里以及如何完成的?是在Web服务器端还是在浏览器中?

更多关于Golang中Webassembly报错:userCurrent未定义问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我刚刚检查了 github.com/lib/pq/conn.go 的第 321 行,没有看到任何对 userCurrent 的引用。你能 go get 那个包然后再试一次吗?

请查看这里的用例页面。WebAssembly 的目标似乎是让 CPU 密集型的客户端代码运行得比用 JavaScript 编写时更高效。如果你正在开发浏览器内游戏、执行图像识别、VR、CAD 等,那么使用 WebAssembly 是有意义的。我不认为它的目标是消除对 Web 服务器的需求。

你不能直接从命令行运行 WebAssembly 模块。WebAssembly 模块是在网页浏览器中客户端运行的。你需要一个网页,通过类似以下代码将你的模块加载到浏览器中:

WebAssembly.instantiateStreaming(fetch('main.wasm'), importObject) // ...

然后,你就可以从运行在浏览器中的 JavaScript 引用你的 main.wasm 模块中暴露的函数。

Sibert:

我注释掉了 lib/pq(如果我正在使用 sqlx,还需要 lib/pq 吗?)

lib/pq 是 PostgreSQL 数据库驱动程序。没有它,你将无法使用 PostgreSQL 数据库。

Sibert:

但我无法在 Mac 上启动可执行文件。

如果你只想在你的 Mac 上运行它,为什么要构建一个 Wasm 模块呢?为什么不直接构建适用于 Mac 的版本呢?

skillian:

你的 main.wasm 文件需要像其他 JavaScript 脚本一样,对你的 Web 应用程序是可访问的。

感谢你的回答。看来我并没有完全理解 wasm 的概念。

我原本的理解是 wasm 就像应用程序一样在浏览器中运行。但我还需要一个服务器吗?哪些部分应该在服务器上,哪些部分应该在浏览器中?

目前关于 wasm 的例子很少,我测试过的所有例子加载时间都很长,但运行起来更像一个桌面应用程序。

skillian:

您必须修改 lib/pq 的源代码,使其不再需要那个 userCurrent 函数。

我注释掉了 lib/pq(如果我正在使用 sqlx,还需要 lib/pq 吗?),然后 go build 成功了。但我无法在 Mac 上启动可执行文件。我哪里做错了?

$ GOOS=js GOARCH=wasm go build -o main.wasm
$ ./main.wasm
-bash: ./main.wasm: cannot execute binary file

skillian:

你能先 go get 那个包然后再试一次吗?

没有区别。还有其他建议吗?

$ GOOS=js GOARCH=wasm go build -o main.wasm  # github.com/lib/pq
../../github.com/lib/pq/conn.go:321:13: undefined: userCurrent

$ go get github.com/lib/pq

$ GOOS=js GOARCH=wasm go build -o main.wasm # github.com/lib/pq
../../github.com/lib/pq/conn.go:321:13: undefined: userCurrent

skillian:

WebAssembly.instantiateStreaming(fetch(‘main.wasm’), importObject)

这个方法不起作用。浏览器怎么知道 main.wasm 在哪里?

skillian:

lib/pq 是 Postgres SQL 数据库驱动。没有它,你就无法使用 Postgres 数据库。

那么问题一定是 lib/pq 损坏了或者没有更新?

skillian:

如果你只是想在你的 Mac 上运行,为什么要构建一个 Wasm 模块?为什么不直接为 Mac 构建呢?

我正在研究这个网站

http://94.237.92.101:3030/mytopics

在使用 WebAssembly 时可能的外观和感觉。但看起来 Go 语言在这方面还没有准备好投入生产环境?

好的,如果我使用 git blame 查看 conn.go 文件,并回溯到最后一次修改第 321 行的提交(提交 cd7087504b4639a9b67e108f365062ab26335e8b),当我向上滚动查看时,会发现第 321 行现在包含了一个对 userCurrent 函数的调用。我建议使用 GitHub 上的最新代码进行更新,因为你手上的代码似乎有些过时了。

无论如何,如果我查看这个函数是在哪里定义的,会发现有一个 user_posix.go 和一个 user_windows.go 文件。这两个文件的构建约束都不适用于 Wasm,因此在为 Wasm 构建时,这个函数就没有被定义。你需要修改 lib/pq 的源代码,要么让它不再需要这个 userCurrent 函数,要么自己为 wasm 实现它。

skillian:

skillian:

WebAssembly.instantiateStreaming(fetch(‘main.wasm’), importObject)

这行不通。浏览器怎么知道 main.wasm 在哪里?

你的 main.wasm 文件需要像其他 JavaScript 脚本一样,能够被你的 Web 应用程序访问到。

skillian:

skillian:

lib/pq 是 PostgreSQL 数据库驱动。没有它,你就无法使用 PostgreSQL 数据库。

所以一定是 lib/pq 损坏了或者没有更新?

lib/pq 几乎可以肯定是为了在服务器端使用的。你的浏览器不应该直接连接到后端数据库。lib/pq 的开发者很可能没有实现对 Wasm 的支持。

Sibert:

但这在 Go 中似乎还没有为生产环境做好准备?

我上次听说,它还没有为生产环境做好准备,但这只是因为整个 Go 运行时都需要被编译进去,所以 Go 的 Wasm 模块与 C++ 或 C 的 Wasm 模块相比非常庞大。据我所知,它是可以工作的并且是稳定的,但初始化时间比普通的 C 语言要长得多。

我认为你不应该在浏览器内运行与数据库通信的代码。即使你成功将 lib/pq 编译为 wasm,我也不知道它是否真的能工作。我认为 Wasm 环境在设计上就被限制进行原始套接字连接,所以我不确定你是否能够连接到数据库。

这个错误是因为 lib/pq 包在编译到 WebAssembly 时调用了 user.Current() 函数,而该函数在 wasm 环境中不可用。os/user 包在 wasm 目标平台下没有完整的实现。

解决方案:

  1. 使用构建标签排除 lib/pq(推荐): 由于 WebAssembly 通常在浏览器中运行,而数据库连接一般在后端服务器,你可能需要将前端(wasm)和后端代码分离。

    // 在你的 wasm 入口文件添加构建标签
    //go:build wasm
    // +build wasm
    
    package main
    
    // 避免导入 lib/pq
    
  2. 如果必须在 wasm 中使用数据库连接,可以尝试使用纯 Go 的数据库驱动,如 modernc.org/sqlite(适用于 SQLite):

    import (
        _ "modernc.org/sqlite"
        "database/sql"
    )
    
    func main() {
        db, err := sql.Open("sqlite", "file::memory:")
        // ... 使用数据库
    }
    
  3. lib/pq 创建 wasm 兼容的补丁(临时方案): 在项目中创建补丁文件覆盖 userCurrent 函数:

    // 在编译前替换或修改 lib/pq 的 conn.go 文件
    // 将 userCurrent 函数替换为返回空值的实现
    func userCurrent() (string, error) {
        return "", nil
    }
    

示例:分离前端代码的构建方式:

// main_wasm.go
//go:build wasm
// +build wasm

package main

import "syscall/js"

func main() {
    // 纯前端逻辑,不导入数据库相关包
    js.Global().Set("goFunc", js.FuncOf(jsCallback))
    <-make(chan bool)
}
// main_server.go
//go:build !wasm
// +build !wasm

package main

import (
    "database/sql"
    _ "github.com/lib/pq"
)

func main() {
    // 后端服务器逻辑,正常使用 lib/pq
    db, _ := sql.Open("postgres", "user=postgres dbname=test")
    defer db.Close()
}

编译命令保持不变:

GOOS=js GOARCH=wasm go build -o main.wasm

这样就能避免 wasm 编译时对 user.Current() 的依赖。

回到顶部