I have a vue.js 3 frontend, and I am calling a Golang backend via grpc-gateway
. I have been at this for a while but I see light at the end of the tunnel.
I am currently facing a CORS issue. However, I am reading conflicting information on how to handle it. Therefore, I want to post and hopefully it helps someone.
Here is the code on how I init my mux server for GRPC (gateway)
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()
}
Here is where I believe I should add the cors config, but I am not sure this is how I set it up in the server.go file..
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",
)
})
error in console:
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'
I am not sure where to add something like
func enableCors(w *http.ResponseWriter) {
(*w).Header().Set("Access-Control-Allow-Origin", "*")
}
and I feel the golang GRPC gateway should have something built in but I cannot find anything?
Any advice would be greatly appreciated.
----- update 1 -----
I have tried
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)
})
}
and
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)
})
}
and
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)
})
}
in conjuction with
func serveSwagger(mux *http.ServeMux, swaggerPath string) {
fileServer := http.FileServer(http.Dir(swaggerPath))
prefix := "/swagger-ui"
mux.Handle(prefix, http.StripPrefix(prefix, fileServer))
}
and still have the same issue.. Very frustrating
Based on the latest error you've provided in a comment:
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.
Your browser is sending a preflight request (OPTIONS
HTTP method) to ascertain whether the desired cross origin request can be made.
And the server is responding with a non-2xx response.
I suspect this is because your enableCors
functions are propagating the request to the grpc-gateway handler, which is unhappy with the OPTIONS
HTTP method and returning an error status, probably:
< 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":[]}
So to avoid that, you'd want to not propagate the request further in the case of a preflight request being made, e.g.
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)
})
}
However, the above is likely still not a reasonable implementation of CORS handling. You should look to use an existing package for this, e.g. github.com/rs/cors, which will handle this in a reasonable fashion, and also deal with any potential gotchas, etc.
So importing github.com/rs/cors
and then doing something like:
server.Handler = cors.AllowAll().Handler(swMux)
should get you started by allowing everything through. The library will allow you to tailor to specific origins, HTTP methods, etc, as required.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With