每当我try 从ANGLE应用程序向GO服务器发送HTTP请求时,都会得到以下响应:

Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

我添加了错误响应中详细说明的标头,但错误仍然存在.

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)
}

推荐答案

我注意到的第一个问题是:

AllowedMethods: []string{"GET, POST"},

这应该是:

AllowedMethods: []string{"GET", "POST"},(或较不容易出错的[]string{http.MethodGet, http.MethodPost})

按照the docs,这是默认值(所以你可以省略它):

AllowedMethods []string:允许客户端对跨域请求使用的方法列表.默认值为简单方法(GET和POST).

我的下一个问题是"什么是源";CORS是"跨域资源共享",aims to是"防止从一个源运行的客户端Web应用程序获取从另一个源检索的数据",因此了解发出请求的页面的源是很重要的.您允许http://localhost:4200(AllowedOrigins: []string{"http://localhost:4200"}),所以我假设您有两个服务器在本地主机上运行(但如果不是这样的话也不会感到惊讶).如果您希望允许所有来源,则使用"*";对于测试,我将使用test-cors.org--只需转到该站点,输入URL,例如"http://127.0.0.1:8080/weather/welcome","进入"远程URL",然后点击"发送请求"进行测试.

你的代码有点令人困惑(例如,(s *Server) ServeHTTP没有被使用--在这里提问时,请目标是提供一个minimal, reproducible, example),所以我简化了一些事情,希望下面的内容能让你找到正确的方向.

package main

import (
    "context"
    "fmt"
    "net/http"

    "github.com/gorilla/mux"
    "github.com/rs/cors"
)

func main() {
    s, err := NewServer()
    if err != nil {
        panic(err)
    }
    s.Run(context.Background())
}

type Server struct {
    router *mux.Router
}

func NewServer() (*Server, error) {
    router := mux.NewRouter()
    Register(router)
    server := Server{
        router: router,
    }
    return &server, nil
}

func (s *Server) Run(ctx context.Context) {
    cors := cors.New(cors.Options{
        AllowedMethods: []string{http.MethodGet, http.MethodPost},
        AllowedOrigins: []string{"https://www.test-cors.org"},
        // AllowedOrigins: []string{"*"},
        AllowedHeaders: []string{"Content-Type", "Accept"},
    })

    server := http.Server{
        Addr:    fmt.Sprintf(":%d", 8080),
        Handler: cors.Handler(s.router),
    }

    fmt.Println(server.ListenAndServe())
}

type handler struct{}

func Register(r *mux.Router) {
    handler := handler{}

    r.HandleFunc("/", handler.Index).Methods(http.MethodGet)
    r.HandleFunc("/weather/welcome", handler.Test).Methods(http.MethodGet)
}

// Index - Provide a simple page with a link to the other page to simplify testing
func (h *handler) Index(w http.ResponseWriter, _ *http.Request) {
    w.Write([]byte(`<a href="weather/welcome" >Test Link</a>`))
}

// The real page
func (h *handler) Test(w http.ResponseWriter, _ *http.Request) {
    fmt.Println("Test Called")
    w.Write([]byte("all OK"))
}

Go相关问答推荐

区分Terminal和Hook Zerolog Go中的错误级别日志(log)输出

使用Gorm创建自定义连接表

VS代码,Golang格式顽固的情况与switch / case

CGO Linux到Windows交叉编译中的未知类型名称

创建使用逗号而不是加号分隔OU的CSR

为什么没有正确生成这些元组?

文件路径.Abs()未在结果中提供子目录

如何解决构建Docker Compose时的权限被拒绝问题

在 Windows 11 上运行 go mod tidy 时的 gitlab 权限问题

这是实现超时的常见方法,为什么 time.After 不起作用

Golang:如何在不转义每个动作的情况下呈现模板的模板?

如何使用 sync.WaitGroup 来执行所有的 goroutine?

Golang 创建一个带有处理程序的模拟数据库并使用接口调用数据库

golang yaml 马歇尔网址

CBC Decrypter 解密加密文本,但部分文本被随机字符替换

无法使用 Golang 扫描文件路径

为什么此代码在运行命令 error="exec: not started" 时出现错误?

vs 代码调试 go 测试不通过标志

如何从 tinygo webassembly 目标返回对象

try 执行`go test ./... -v`时,Golang中有没有办法设置标志