go - CORS grpc 网关 GoLang

标签 go grpc-go grpc-gateway

我有一个 vue.js 3 前端,我正在通过 grpc-gateway 调用 Golang 后端。我已经这样做了一段时间,但我看到了隧道尽头的曙光。

我目前面临 CORS 问题。但是,我正在阅读有关如何处理它的相互矛盾的信息。因此,我想发帖并希望它对某人有所帮助。

这是我如何为 GRPC(网关)初始化多路复用服务器的代码

func RunHttpServer(server *http.Server, httpEndpoint, grpcEndpoint, swaggerPath string) (err error) {
    server.Addr = httpEndpoint

    ctx, cancel := context.WithCancel(context.Background())

    defer cancel()

    // Register gROC server endpoint
    mux := runtime.NewServeMux(
        runtime.WithErrorHandler(func(ctx context.Context,
            mux *runtime.ServeMux,
            marshaler runtime.Marshaler,
            w http.ResponseWriter, r *http.Request,
            err error,
        ) {
            s, ok := status.FromError(err)
            if ok {
                if s.Code() == codes.Unavailable {
                    err = status.Error(codes.Unavailable, ErrUnavailable)
                }
            }

            runtime.DefaultHTTPErrorHandler(ctx, mux, marshaler, w, r, err)

        }),
    )

    opts := []grpc.DialOption{
        grpc.WithTransportCredentials(insecure.NewCredentials()),
        grpc.WithChainUnaryInterceptor(),
    }

    if err = api.RegisterApiServiceHandlerFromEndpoint(ctx, mux, grpcEndpoint, opts); err != nil {
        return
    }

    swMux := http.NewServeMux()
    swMux.Handle("/", mux)
    serveSwagger(swMux, swaggerPath)

    server.Handler = swMux

    return server.ListenAndServe()

}

这是我认为我应该添加 cors 配置的地方,但我不确定这是我在 server.go 文件中设置它的方式..

var httpServer http.Server

// Run Http Server with gRPC gateway
g.Go(func() error {
    fmt.Println("Starting Http sever (port {}) and gRPC gateway (port {})",
        strconv.Itoa(cfg.Server.HTTPPort),
        strconv.Itoa(cfg.Server.GRPCPort),
    )

    return rest.RunHttpServer(
        &httpServer,
        ":"+strconv.Itoa(cfg.Server.HTTPPort),
        ":"+strconv.Itoa(cfg.Server.GRPCPort),
        "/webapi",
    )
})

控制台错误:

Access to XMLHttpRequest at 'http://localhost:8080/v1/test' from origin 'http://localhost:9000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin'

我不确定在哪里添加类似的东西

func enableCors(w *http.ResponseWriter) {
    (*w).Header().Set("Access-Control-Allow-Origin", "*")
}

我觉得 golang GRPC 网关应该内置了一些东西,但我找不到任何东西?

如有任何建议,我们将不胜感激。

----- 更新 1 -----

我试过了

func enableCors(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "http://localhost:9000")
        w.Header().Set("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, HEAD, OPTIONS")
        h.ServeHTTP(w, r)
    })
}

func enableCors(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "*")
        w.Header().Set("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, HEAD, OPTIONS")
        h.ServeHTTP(w, r)
    })
}

func enableCors(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "http://localhost")
        w.Header().Set("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, HEAD, OPTIONS")
        h.ServeHTTP(w, r)
    })
}

连同

func serveSwagger(mux *http.ServeMux, swaggerPath string) {
    fileServer := http.FileServer(http.Dir(swaggerPath))
    prefix := "/swagger-ui"
    mux.Handle(prefix, http.StripPrefix(prefix, fileServer))
}

仍然有同样的问题..非常令人沮丧

最佳答案

根据您在评论中提供的最新错误:

Access to XMLHttpRequest at 'localhost:8080/v1/test' from origin 'localhost:9000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.

您的浏览器正在发送 preflight request (OPTIONS HTTP 方法)以确定是否可以发出所需的跨源请求。

并且服务器正在响应非 2xx 响应。

我怀疑这是因为您的 enableCors 函数正在将请求传播到 grpc-gateway 处理程序,它对 OPTIONS HTTP 方法不满意并返回错误状态,可能:

< HTTP/1.1 501 Not Implemented
< Content-Type: application/json
< Vary: Origin
< Date: Fri, 25 Nov 2022 11:17:52 GMT
< Content-Length: 55
< 
{"code":12,"message":"Method Not Allowed","details":[]}

因此,为避免这种情况,您希望在发出预检请求的情况下进一步传播请求,例如

func enableCors(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "http://localhost:9000")
        w.Header().Set("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, HEAD, OPTIONS")
        if r.Method == http.MethodOptions {
            w.WriteHeader(http.StatusNoContent)
            return
        }
        h.ServeHTTP(w, r)
    })
}

但是,以上可能仍然不是 CORS 处理的合理实现。您应该为此使用现有的软件包,例如github.com/rs/cors ,它将以合理的方式处理这个问题,并处理任何潜在的陷阱等。

所以导入 github.com/rs/cors 然后做类似的事情:

server.Handler = cors.AllowAll().Handler(swMux)

应该让一切通过。该库将允许您根据需要定制特定来源、HTTP 方法等。

关于go - CORS grpc 网关 GoLang,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74510810/

相关文章:

datetime - 将 Go 时间从 UnixDate 转换为 RFC3339 无法保留时区

c - 从 Go 代码修改 C void* 字节数组

docker - 试图在docker sdk入口点内使用$(command)

grpc - grpc-go 中的 session 和远程 IP 地址

go - 无法使用 protobuf 生成空数组/golang 代码片段

go - 按顺序同时执行作业

go - 使用protoc生成golang代码时导入和使用其他.proto文件出错

go - 如何在拦截器中安全地将值添加到grpc ServerStream

python - 如何从 grpc-gateway 后面的 python 服务发送状态为 non-ok 的响应消息?

go - 如何访问代理的 grpc 服务中的请求 header 。 golang 中的 grpc 网关