Golang API遇到奇怪错误:curl和Bruno测试正常但JavaScript fetch无法使用
Golang API遇到奇怪错误:curl和Bruno测试正常但JavaScript fetch无法使用 我是Go语言的新手。我很喜欢Go,但这个问题让我快疯了。
以下是相关的Go代码。它的作用仅仅是发送一个TCP字符串命令。
type CasparRequest struct {
Command string
}
mux.HandleFunc("/casparconnecting", func(w http.ResponseWriter, req *http.Request) {
enableCors(&w)
connection, err := amcp.Dial("127.0.0.1:5250")
if err != nil {
// log.Fatal(err)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
}
if connection == nil {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Connection has not been established"))
return
}
defer connection.Close()
var command CasparRequest
err1 := json.NewDecoder(req.Body).Decode(&command)
if err1 != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
fmt.Println("the command sent", command.Command)
code, replyData, err := connection.Do(command.Command)
if err != nil {
log.Fatal(err)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
}
fmt.Println("replyCode", code)
fmt.Println("replyCode", replyData)
replyString := fmt.Sprintf("%v", replyData)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK) // Set your code here, after setting your headers
w.Write([]byte(replyString))
// defer c.Close()
})
以下的curl请求可以正常工作:
curl --header "Content-Type: application/json" --request POST --data '{"command":"PLAY 1-1 myfile000.mp4"}' http://localhost:8080/casparconnecting
然而,一旦我从浏览器发起请求,服务器就会发生恐慌(panic)。
const fetched = await fetch("http://localhost:8080/casparconnecting", {
headers: {
"Content-Type": "application/json",
},
method: "POST",
body: JSON.stringify({ command: "PLAY 1-1 myfile000.mp4" }),
});
这是JavaScript POST请求的详细信息:
{
"args": {},
"data": "{\"command\":\"PLAY 1-1 myfile000.mp4\"}",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate, br, zstd",
"Accept-Language": "en-GB,en-US;q=0.9,en;q=0.8",
"Connection": "keep-alive",
"Content-Length": "36",
"Content-Type": "application/json",
"Host": "localhost:9090",
"Origin": "http://localhost:5173",
"Referer": "http://localhost:5173/",
"Sec-Ch-Ua": "\"Chromium\";v=\"128\", \"Not;A=Brand\";v=\"24\", \"Google Chrome\";v=\"128\"",
"Sec-Ch-Ua-Mobile": "?0",
"Sec-Ch-Ua-Platform": "\"Linux\"",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-site",
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
},
"json": {
"command": "PLAY 1-1 myfile000.mp4"
},
"method": "POST",
"origin": "172.17.0.1",
"url": "http://localhost:9090/anything"
}
这是curl请求的详细信息:
{
"args": {},
"data": "{\"command\":\"play 1-1 myfile000.mp4\"}",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Content-Length": "36",
"Content-Type": "application/json",
"Host": "localhost:9090",
"User-Agent": "curl/7.81.0"
},
"json": {
"command": "play 1-1 myfile000.mp4"
},
"method": "POST",
"origin": "172.17.0.1",
"url": "http://localhost:9090/anything"
}
为什么JavaScript请求会在这里导致问题?即使我从浏览器复制请求作为curl命令,它也能工作。但我不明白这怎么会导致后端出错。 以下是我的Go代码失败的方式:
2024/09/04 12:58:22 http: panic serving [::1]:34408: runtime error: invalid memory address or nil pointer dereference goroutine 6 [running]: net/http.(*conn).serve.func1() /usr/local/go/src/net/http/server.go:1898 +0xbe panic({0x6b2360?, 0x93e4f0?}) /usr/local/go/src/runtime/panic.go:770 +0x132 main.main.func3({0x785120, 0xc0000e6620}, 0xc0000ca360) /home/john_doe/repos/basketball-backend-go/main.go:139 +0x7f5 net/http.HandlerFunc.ServeHTTP(0xc0000bab60?, {0x785120?, 0xc0000e6620?}, 0x651dda?) /usr/local/go/src/net/http/server.go:2166 +0x29 net/http.(*ServeMux).ServeHTTP(0x467db9?, {0x785120, 0xc0000e6620}, 0xc0000ca360) /usr/local/go/src/net/http/server.go:2683 +0x1ad net/http.serverHandler.ServeHTTP({0xc0000b8cf0?}, {0x785120?, 0xc0000e6620?}, 0x6?) /usr/local/go/src/net/http/server.go:3137 +0x8e net/http.(*conn).serve(0xc0000fe000, {0x7856b0, 0xc0000b8c00}) /usr/local/go/src/net/http/server.go:2039 +0x5e8 created by net/http.(*Server).Serve in goroutine 1 /usr/local/go/src/net/http/server.go:3285 +0x4b4
请帮帮我。我不明白问题可能出在哪里。
更多关于Golang API遇到奇怪错误:curl和Bruno测试正常但JavaScript fetch无法使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
哇,非常感谢,这篇博客真是太有用了。我从来都不知道!快速浏览了一下MDN和Stack Overflow,我还以为options方法的catch就足够了。
我本来只是想只用标准库来学习更多东西,因为大家都这么推荐。 谢谢!
更多关于Golang API遇到奇怪错误:curl和Bruno测试正常但JavaScript fetch无法使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
答案:
这是一个由浏览器发送带有 OPTIONS 方法的预检请求引起的 CORS 错误。浏览器在网络标签页中不会显示此请求。 使用 VSCode 中的调试器解决了问题。
我通过以下代码片段修复了它:
if req.Method == "OPTIONS" {
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Origin, Accept, token")
w.WriteHeader(http.StatusOK)
return
}
你可能需要使用一个中间件库来处理CORS;这比看起来要复杂得多。
例如,req.Method == "OPTIONS" 的条件过于严格,因为它会“捕获”所有 OPTIONS 请求,但并非所有 OPTIONS 请求都是 CORS 预检请求;关于此主题的更多信息可在此处找到。
问题出在你的错误处理逻辑上。当 json.NewDecoder(req.Body).Decode(&command) 失败时,你使用了错误的错误变量。
这是有问题的代码行:
if err1 != nil {
http.Error(w, err.Error(), http.StatusBadRequest) // 这里使用了 err 而不是 err1
return
}
当 JavaScript 的 fetch 请求发送时,可能由于 CORS 预检请求或其他原因,导致 JSON 解码失败,这时 err1 不为 nil,但你却尝试使用 err 变量(这是之前连接错误检查的变量),此时 err 为 nil,所以 err.Error() 会引发空指针解引用恐慌。
修复方案:
type CasparRequest struct {
Command string
}
mux.HandleFunc("/casparconnecting", func(w http.ResponseWriter, req *http.Request) {
enableCors(&w)
// 处理 CORS 预检请求
if req.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}
var command CasparRequest
// 正确使用 err1 变量
err := json.NewDecoder(req.Body).Decode(&command)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest) // 使用正确的错误变量
return
}
fmt.Println("the command sent", command.Command)
connection, err := amcp.Dial("127.0.0.1:5250")
if err != nil {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(fmt.Sprintf(`{"error":"%v"}`, err)))
return
}
defer connection.Close()
code, replyData, err := connection.Do(command.Command)
if err != nil {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(fmt.Sprintf(`{"error":"%v"}`, err)))
return
}
fmt.Println("replyCode", code)
fmt.Println("replyData", replyData)
replyString := fmt.Sprintf("%v", replyData)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(replyString))
})
同时确保你的 enableCors 函数正确处理了 CORS 头部:
func enableCors(w *http.ResponseWriter) {
(*w).Header().Set("Access-Control-Allow-Origin", "*")
(*w).Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
(*w).Header().Set("Access-Control-Allow-Headers", "Content-Type")
}
这样修改后,当 JSON 解码失败时,会正确返回错误信息而不是引发恐慌。

