Golang文件服务器子路径下HTML无法加载.wasm文件问题
我用Golang搭建带子路径的文件服务器,现有代码如下:
func main() { fs := http.FileServer(http.Dir("../../dist/")) http.Handle("/", fs) http.Handle("/a/", http.StripPrefix("/a/", fs)) http.ListenAndServe(":8081", nil) }
../../dist/目录下包含index.html和多个.wasm文件。访问:8081/时文件服务器运行正常,但访问:8081/a/时,index.html可正常加载,但其引用的.wasm文件加载失败。HTML代码如下:
<html> <head> <link rel="preload" href="/start-4f9b00c561355aee_bg.wasm" as="fetch" type="application/wasm" crossorigin=""> <link rel="modulepreload" href="/start-4f9b00c561355aee.js"> </head> <body> <script type="module"> import init from '/start-4f9b00c561355aee.js'; init('/start-4f9b00c561355aee_bg.wasm'); </script> </body> </html>
我已尝试添加http.StripPrefix(如上代码所示),甚至设置Header().Set("content-type", "application/wasm"),但都无法让/a/路径正常加载.wasm文件。请问我遗漏了什么?
核心问题分析
你遇到的问题根源在HTML资源的引用路径:所有.wasm、.js资源都是以/开头的绝对路径。当浏览器访问/a/时,会直接请求/start-xxx.wasm(根路径下的资源),而不是/a/start-xxx.wasm。虽然你的Go代码把/a/映射到了dist目录,但浏览器根本没往/a/路径发送资源请求,自然找不到文件。
解决方案
方案1:修改HTML为相对路径引用
把所有绝对路径的资源引用改成相对路径(去掉开头的/),让浏览器自动根据当前URL拼接路径:
<html> <head> <link rel="preload" href="start-4f9b00c561355aee_bg.wasm" as="fetch" type="application/wasm" crossorigin=""> <link rel="modulepreload" href="start-4f9b00c561355aee.js"> </head> <body> <script type="module"> import init from './start-4f9b00c561355aee.js'; init('./start-4f9b00c561355aee_bg.wasm'); </script> </body> </html>
这样访问/a/时,浏览器会请求/a/start-xxx.wasm,Go的StripPrefix("/a/", fs)会去掉前缀/a/,正确映射到dist目录下的对应文件。
方案2:通过前端构建工具设置基础路径(适合有构建流程的项目)
如果你的前端是用Vite、Webpack等工具构建的,可以直接配置base选项为/a/,构建后所有资源路径会自动带上/a/前缀:
- 比如Vite的
vite.config.js:
export default { base: '/a/' }
构建后的HTML资源引用会变成/a/start-xxx.wasm,这样不管访问/还是/a/,资源请求路径都能被Go的路由正确处理:
- 访问
/时,请求/a/start-xxx.wasm会被http.Handle("/a/", ...)路由处理; - 访问
/a/时,请求/a/start-xxx.wasm同样会被该路由处理。
方案3:自定义Go Handler统一处理路径(不修改HTML的可选方案)
如果不想改动前端代码,可以自定义一个Handler,判断请求路径是否属于子路径,再转发到对应的文件服务器:
func main() { distFS := http.FileServer(http.Dir("../../dist/")) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { // 检查请求是否来自/a/路径 if strings.HasPrefix(r.URL.Path, "/a/") { http.StripPrefix("/a/", distFS).ServeHTTP(w, r) return } // 其他请求直接用根路径的文件服务器 distFS.ServeHTTP(w, r) }) http.ListenAndServe(":8081", nil) }
不过这个方案治标不治本,因为浏览器请求的还是根路径资源,只是通过Go Handler强制转发,不如前两种方案优雅。
内容的提问来源于stack exchange,提问作者ccQpein

