You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

本地Go JSON-RPC对接浏览器原生JS报Failed to fetch修复方案

问题解答

本地环境能否实现通信

完全可以。浏览器JS和本地运行的Go服务通过JSON-RPC通信不存在环境层面的限制,你遇到的TypeError: Failed to fetch是代码实现错误导致的,和本地环境无关。

核心错误点

  • 协议完全不匹配:你当前写的Go服务是直接在TCP协议层挂载JSON-RPC处理器,根本没有实现HTTP协议解析逻辑。而浏览器fetchAPI发送的是标准HTTP请求,服务端收到后无法识别HTTP报文格式,自然不会返回符合HTTP规范的响应,直接触发fetch失败。
  • 跨域拦截:本地直接打开的HTML文件默认走file://协议,和http://127.0.0.1:1234属于不同源,就算服务端支持HTTP,没有配置CORS响应头的话,浏览器会直接拦截响应,同样会报fetch错误。
  • 前端代码细节错误:你写的请求路径/rpc/v1在服务端没有对应路由,响应回调里错误引用了未定义的error变量,就算请求通了也拿不到正确结果。

可直接运行的修正代码

Go服务端代码

核心改动是把裸TCP服务改成HTTP服务,增加CORS中间件处理跨域和预检请求,适配HTTP连接到JSON-RPC处理器:

package main

import (
	"io"
	"log"
	"net/http"
	"net/rpc"
	"net/rpc/jsonrpc"
)

type HelloService struct{}

func (p *HelloService) Hello(request string, reply *string) error {
	*reply = "Hello " + request
	return nil
}

// 跨域处理中间件,本地调试用
func corsMiddleware(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
		w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
		// 处理浏览器跨域预检请求
		if r.Method == http.MethodOptions {
			w.WriteHeader(http.StatusOK)
			return
		}
		next.ServeHTTP(w, r)
	}
}

// JSON-RPC HTTP请求处理器
func jsonRPCHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	// 包装HTTP连接为JSON-RPC需要的ReadWriteCloser接口
	conn := &httpRPCConn{
		reader: r.Body,
		writer: w,
	}
	jsonrpc.ServeConn(conn)
}

type httpRPCConn struct {
	reader io.Reader
	writer io.Writer
}

func (h *httpRPCConn) Read(p []byte) (n int, err error) {
	return h.reader.Read(p)
}

func (h *httpRPCConn) Write(p []byte) (n int, err error) {
	return h.writer.Write(p)
}

func (h *httpRPCConn) Close() error {
	if rc, ok := h.reader.(io.Closer); ok {
		return rc.Close()
	}
	return nil
}

func main() {
	rpc.RegisterName("HelloService", new(HelloService))
	// 注册和前端请求对应的路由
	http.HandleFunc("/rpc/v1", corsMiddleware(jsonRPCHandler))
	log.Println("RPC服务已启动,监听1234端口")
	log.Fatal(http.ListenAndServe(":1234", nil))
}

前端client.html代码

修正回调里的变量引用错误,增加结果展示逻辑:

<!DOCTYPE html>
<html>
<body>
<p id="demo">Fetch a file to change this text.</p>
<script>
fetch('http://127.0.0.1:1234/rpc/v1', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      jsonrpc: '1.0',
      method: 'HelloService.Hello',
      params: ["popcontent"],
      id: "jsonrpc"
    })
  })
.then((response) => {
  if (!response.ok) {
    throw new Error(`请求异常,状态码:${response.status}`)
  }
  return response.json()
})
.then((res) => {
  console.log("RPC返回结果:", res)
  document.getElementById('demo').textContent = res.result
})
.catch((error) => {
  console.log("请求错误:", error)
});
</script>
</body>
</html>

运行验证

  1. 先启动Go服务,控制台会打印服务启动日志
  2. 直接双击打开client.html,浏览器控制台会输出返回结果{id: 'jsonrpc', result: 'Hello popcontent', error: null},页面上的文字也会同步替换成返回的内容。

注:代码里的CORS头Access-Control-Allow-Origin: *仅适合本地调试使用,如果后续把前端部署到正式服务,需要把这个值改成对应前端的域名,避免安全风险。

内容的提问来源于stack exchange,提问作者vanessa boehr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 17:57:34