Angular请求Go后端遇CORS预检403错误,求解决方案
使用Angular前端向Go后端发送HTTP请求时,尽管已配置跨域相关头,仍收到以下错误:
Access to XMLHttpRequest at 'http://localhost:3000/rcVolume' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
相关代码配置如下:
Go 主函数
func main() { store, err := NewPostgresStore() if err != nil { log.Fatal(err) } if err := store.Init(); err != nil { log.Fatal(err) } server := NewAPIServer(":3000", store) server.Run() }
Go 服务器配置
func (s *APIServer) Run() { router := mux.NewRouter() router.HandleFunc("/rcVolume", makeHTTPHandleFunc(s.handleRcVolume)) log.Println("JSON API Server running on port: ", s.listenAddr) headers := handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type", "Authorization"}) origins := handlers.AllowedOrigins([]string{"*"}) methods := handlers.AllowedMethods([]string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}) http.ListenAndServe(s.listenAddr, handlers.CORS(headers, origins, methods)(router)) }
Go 请求处理方法
func (s *APIServer) handleRcVolume(w http.ResponseWriter, r *http.Request) error { if r.Method == "GET" { return s.handleGetRcVolumes(w, r) } if r.Method == "POST" { return s.handleCreateRcVolume(w, r) } return fmt.Errorf("method not allowed %s", r.Method) } func (s *APIServer) handleGetRcVolumes(w http.ResponseWriter, r *http.Request) error { rcVolumes, err := s.store.GetRcVolumes() if err != nil { return err } return writeJSON(w, http.StatusOK, rcVolumes) } func writeJSON(w http.ResponseWriter, status int, v any) error { w.Header().Set("Content-Type", "application/json") w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "DELETE, POST, GET, OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With") w.WriteHeader(status) return json.NewEncoder(w).Encode(v) }
Angular 相关代码
请求头配置
export const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'DELETE, POST, GET, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With' }) };
API服务
@Injectable({ providedIn: 'root' }) export class RcVolumesServiceApi { private url = 'http://localhost:3000' constructor(private httpClient: HttpClient) { } getRcVolumes() { return this.httpClient.get<any[]>('http://localhost:3000/rcVolume', httpOptions) } }
1. 清理Angular请求中的无效头
Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers是服务器响应头,前端无需在请求中携带;且GET请求不需要设置Content-Type: application/json(该设置会触发非简单请求的预检流程)。修改后的请求配置:
// 移除多余的CORS响应头,GET请求无需Content-Type export const httpOptions = { headers: new HttpHeaders({}) }; // 或者直接不传httpOptions给GET请求 getRcVolumes() { return this.httpClient.get<any[]>('http://localhost:3000/rcVolume') }
2. 确保Go后端错误响应也携带CORS头
当前代码中,当请求方法不是GET/POST时,会返回method not allowed错误,若makeHTTPHandleFunc未通过writeJSON处理错误,会导致错误响应缺少CORS头。修改错误处理逻辑:
// 确保错误响应通过writeJSON返回,自动携带CORS头 type apiFunc func(http.ResponseWriter, *http.Request) error func makeHTTPHandleFunc(f apiFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if err := f(w, r); err != nil { writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": err.Error()}) } } }
3. 移除writeJSON中的重复CORS配置
gorilla/handlers的CORS中间件已自动设置跨域头,无需在writeJSON中重复添加,避免配置冲突:
func writeJSON(w http.ResponseWriter, status int, v any) error { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) return json.NewEncoder(w).Encode(v) }
4. 验证预检请求
用curl测试OPTIONS预检请求,确认响应包含正确的CORS头:
curl -X OPTIONS http://localhost:3000/rcVolume -H "Origin: http://localhost:4200" -H "Access-Control-Request-Method: GET"
正常响应应包含Access-Control-Allow-Origin: *、Access-Control-Allow-Methods等头。
内容的提问来源于stack exchange,提问作者Ticu Alexandru-Marian

