Dart仍报'Access-Control-Allow-Origin'头缺失错误,但Go API已配置该头
我之前也踩过这个CORS的坑,结合你的代码和报错来看,问题大概率出在CORS头的设置时机、预检请求处理或者错误处理导致头未发送上,咱们一步步来解决:
1. 确保CORS头在请求处理最开始就设置
看你给出的代码片段,没看到设置Access-Control-Allow-Origin的代码——就算你加了,如果是在数据库查询之后才设置,一旦中间出现panic(比如数据库连接失败、ID转换错误),头根本不会发送给客户端。
正确的做法是在GetJob函数最开头就设置头:
func GetJob(w http.ResponseWriter, r *http.Request) { // 先设置CORS头,不管后续逻辑是否出错 w.Header().Set("Access-Control-Allow-Origin", "*") job := Job{} db, err := gorm.Open("postgres", connString) // 注意用:=避免全局变量覆盖 if err != nil { // 不要用panic,用http.Error返回错误,同时头已经设置完成 http.Error(w, "Could not connect to the database", http.StatusInternalServerError) return } defer db.Close() vars := mux.Vars(r) jobID, err := strconv.Atoi(vars["jobid"]) if err != nil { http.Error(w, "Invalid job ID", http.StatusBadRequest) return } // 后续查询逻辑 if err := db.Debug().Where("id = ?", jobID).First(&job).Error; err != nil { http.Error(w, "Job not found", http.StatusNotFound) return } // 返回JSON响应 w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(job) }
2. 必须处理OPTIONS预检请求
如果你的Dart客户端发送的是非简单请求(比如带自定义头、用PUT/DELETE方法,甚至部分场景下的POST),浏览器会先发送一个OPTIONS预检请求,确认服务器允许跨域。如果API没处理这个请求,浏览器就会抛出CORS错误。
最优雅的方式是用CORS中间件统一处理所有请求,结合gorilla/mux的示例如下:
// 定义CORS中间件 func corsMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // 允许所有来源,也可以指定具体域名 w.Header().Set("Access-Control-Allow-Origin", "*") // 允许的HTTP方法 w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, DELETE") // 允许的请求头 w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization") // 处理OPTIONS预检请求,直接返回200状态码 if r.Method == http.MethodOptions { w.WriteHeader(http.StatusOK) return } // 继续处理原请求 next.ServeHTTP(w, r) }) } // 路由配置时添加中间件 func main() { router := mux.NewRouter() // 把CORS中间件加到最前面,确保所有请求都经过处理 router.Use(corsMiddleware) router.HandleFunc("/jobs/{jobid}", GetJob).Methods("GET") http.ListenAndServe(":8080", router) }
3. 替换panic为错误处理
你代码里的panic会直接终止程序,不仅导致服务不稳定,还会让CORS头无法发送——panic触发时,Go会直接返回500错误,但不会带上你设置的头。用http.Error返回错误状态码,既能优雅处理错误,又能确保CORS头被正常发送。
4. 验证浏览器实际收到的响应头
打开浏览器开发者工具(F12),切换到Network标签,找到你的API请求,查看Response Headers里是否真的存在Access-Control-Allow-Origin: *。如果没有,可能是反向代理(比如Nginx)覆盖了头,这时候需要在代理配置里也添加对应的CORS头。
按照上面的步骤调整后,你的Dart客户端应该就能正常请求API了。
内容的提问来源于stack exchange,提问作者Brooke Norton

