Golang服务跨域报错:请求资源缺失Access-Control-Allow-Origin头
跨域预检请求失败问题排查与解决
问题描述
从Angular应用向Go后端发送HTTP请求时,收到报错:
预检请求未通过跨域检查:请求资源上不存在'Access-Control-Allow-Origin'头。
已手动添加响应头,但问题仍未解决。
相关代码
server.go
package rest import ( "context" "fmt" "net/http" "os" "os/signal" "sync" "syscall" "github.com/gorilla/mux" "github.com/randyVerduguez/randy-verduguez_06122023-BE-challenge/configs" "github.com/randyVerduguez/randy-verduguez_06122023-BE-challenge/http/rest/handlers" "github.com/randyVerduguez/randy-verduguez_06122023-BE-challenge/pkg/db" "github.com/rs/cors" "github.com/sirupsen/logrus" ) type Server struct { logger *logrus.Logger router *mux.Router config configs.Config } func NewServer() (*Server, error) { config, err := configs.NewParsedConfig() if err != nil { return nil, err } database, err := db.Connect(db.ConfigDB{ Host: config.Database.Host, Port: config.Database.Port, User: config.Database.User, Password: config.Database.Password, Name: config.Database.Name, }) if err != nil { return nil, err } log, err := NewLogger() if err != nil { return nil, err } router := mux.NewRouter() handlers.Register(router, log, database) server := Server{ logger: log, config: config, router: router, } return &server, nil } func (s *Server) Run(ctx context.Context) error { cors := cors.New(cors.Options{ AllowedMethods: []string{"GET, POST"}, AllowedOrigins: []string{"http://localhost:4200"}, AllowedHeaders: []string{"Content-Type", "Accept"}, }) server := http.Server{ Addr: fmt.Sprintf(":%d", s.config.ServerPort), Handler: cors.Handler(s.router), } stopServer := make(chan os.Signal, 1) signal.Notify(stopServer, syscall.SIGINT, syscall.SIGTERM) defer signal.Stop(stopServer) serverErrors := make(chan error, 1) var wg sync.WaitGroup wg.Add(1) go func(wg *sync.WaitGroup) { defer wg.Done() s.logger.Printf("REST API listening on %d", s.config.ServerPort) serverErrors <- server.ListenAndServe() }(&wg) select { case err := <-serverErrors: return fmt.Errorf("error: starting REST API server %w", err) case <-stopServer: s.logger.Warn("server recieved STOP signal") err := server.Shutdown(ctx) if err != nil { return fmt.Errorf("graceful shutdown did not complete: %w", err) } wg.Wait() s.logger.Info("server was shutdown gracefully") } return nil } func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "http://localhost:4200") w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS") w.Header().Set("Access-Control-Allow-Credentials", "true") w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, Accept, origin, Cache-Control, X-Requested-With") if r.Method == "OPTIONS" { return } s.router.ServeHTTP(w, r) }
routes.go
package handlers import ( "net/http" "github.com/gorilla/mux" "github.com/jmoiron/sqlx" "github.com/sirupsen/logrus" ) func Register(r *mux.Router, lg *logrus.Logger, db *sqlx.DB) { handler := newHandler(lg, db) r.Use(handler.MiddlewareLogger()) r.HandleFunc("/weather/current", handler.GetCurrentWeather()).Methods(http.MethodPost) r.HandleFunc("/weather/welcome", handler.Test()).Methods(http.MethodGet) }
问题根源与解决方法
你当前代码同时使用了两种CORS处理方式:github.com/rs/cors库和自定义ServeHTTP方法,两者冲突导致CORS头处理混乱;同时rs/cors的配置存在语法错误。
修正
rs/cors的AllowedMethods配置
当前写法[]string{"GET, POST"}是错误的,每个HTTP方法需作为单独字符串元素,且必须包含预检请求用的OPTIONS方法:AllowedMethods: []string{"GET", "POST", "OPTIONS"},移除自定义的
ServeHTTP方法
既然已经用rs/cors库处理CORS,无需再手动编写ServeHTTP设置响应头,两者共存会导致头信息冲突,无法正确处理预检请求。补全必要的CORS配置项
将你自定义ServeHTTP中设置的允许头、凭证支持等配置迁移到rs/cors的选项中,确保覆盖所有需求。
修正后的Run方法中CORS配置部分:
func (s *Server) Run(ctx context.Context) error { cors := cors.New(cors.Options{ AllowedMethods: []string{"GET", "POST", "OPTIONS"}, AllowedOrigins: []string{"http://localhost:4200"}, AllowedHeaders: []string{"Content-Type", "Accept", "Content-Length", "Accept-Encoding", "X-CSRF-Token", "Authorization", "origin", "Cache-Control", "X-Requested-With"}, AllowCredentials: true, }) server := http.Server{ Addr: fmt.Sprintf(":%d", s.config.ServerPort), Handler: cors.Handler(s.router), } // 其余代码保持不变 }
删除整个ServeHTTP方法后,rs/cors库就能正确处理所有CORS相关请求,包括预检OPTIONS请求,不会再出现缺少Access-Control-Allow-Origin头的问题。
内容的提问来源于stack exchange,提问作者Papilo
相关产品推荐
相关产品推荐

