CORS ERROR
muhammadqazi opened this issue · comments
I am making request to my golang api through react js application, i am using mux for the routing, the problem i get everytime is CORS whenever i use mux, however there is no CORS error when i use the golang handleFunc without using any library mux or gin.
…
Versions
go version go1.20.5 darwin/arm64
…
Steps to Reproduce
Just make an api call to http://localhost:9000/ping
…
Expected behavior
No Cors Error
Code Snippets
import gohandlers "github.com/gorilla/handlers"
r := mux.NewRouter()
// test route
r.HandleFunc("ping", func(rw http.ResponseWriter, r *http.Request) {
rw.Write([]byte("pong"))
})
ch := gohandlers.CORS(gohandlers.AllowedOrigins([]string{"*"}))
s := http.Server{
Addr: env.PORT,
Handler: ch(r),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 120 * time.Second,
}
logger.Info("Server started at port", env.PORT)
err = s.ListenAndServe()
I tried everything with custom cors middleware but no luck
my custom middleware
package middlewares
import (
"fmt"
"net/http"
)
// CORS middleware
func CORS(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
fmt.Println("CORS middleware")
// Set CORS headers
rw.Header().Set("Access-Control-Allow-Origin", "*")
rw.Header().Set("Access-Control-Allow-Credentials", "true")
rw.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
rw.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
// Handle preflight requests
if r.Method == "OPTIONS" {
rw.WriteHeader(http.StatusOK)
return
}
fmt.Println(rw.Header())
// Call the next handler
next.ServeHTTP(rw, r)
})
}
nothing seems to work i tried everything.
but when i tried the same one without using gorilla/mux my server respond and i didn't get any cors error
Code Snippet WITHOUT USING MUX - NO CORS ERROR HERE
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
r := http.NewServeMux()
r.HandleFunc("/ping", func(rw http.ResponseWriter, r *http.Request) {
rw.Write([]byte("pong"))
})
middlewareMux := applyMiddleware(r, CORS2)
// func with cors middleware
// http.HandleFunc("/ping", CORS(func(rw http.ResponseWriter, r *http.Request) {
// fmt.Println("ping")
// rw.Write([]byte("cors"))
// }))
fmt.Println("Server running on port 8080")
log.Fatal(http.ListenAndServe(":8080", middlewareMux))
}
func CORS2(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
fmt.Println("CORS middleware")
// Set CORS headers
rw.Header().Set("Access-Control-Allow-Origin", "*")
rw.Header().Set("Access-Control-Allow-Credentials", "true")
rw.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
rw.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
// Handle preflight requests
if r.Method == "OPTIONS" {
rw.WriteHeader(http.StatusOK)
return
}
fmt.Println(rw.Header())
// Call the next handler
next.ServeHTTP(rw, r)
})
}
func applyMiddleware(mux *http.ServeMux, middlewares ...func(http.Handler) http.Handler) http.Handler {
var handler http.Handler = mux
for _, middleware := range middlewares {
handler = middleware(handler)
}
return handler
}
Hi @muhammadqazi I used your example above and I didn't get any CORS error. I can do Ping on browser, postman and fetch from browser console. Here is the code I have used:
package main
import (
"log"
"net/http"
"time"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
)
func YourHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Ping!\n"))
}
func main() {
r := mux.NewRouter()
// Routes consist of a path and a handler function.
r.HandleFunc("/ping", YourHandler)
// Bind to a port and pass our router in
ch := handlers.CORS(handlers.AllowedOrigins([]string{"*"}))
//log.Fatal(http.ListenAndServe(":8000", ch(r)))
s := http.Server{
Addr: "localhost:8000",
Handler: ch(r),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 120 * time.Second,
}
log.Fatal(s.ListenAndServe())
}
Could you help us understand where is the problem or if I am doing something different. It would be better if you can write steps to replicate with complete code.
Hi @muhammadqazi, both examples work for me, the only error a found was when you write the handler using the mux library in the path, you forgot the /
in the path, it must be /ping
. Maybe was a copy-paste error here, you wrote:
// test route
r.HandleFunc("ping", func(rw http.ResponseWriter, r *http.Request) {
rw.Write([]byte("pong"))
})
And mus be:
// test route
r.HandleFunc("/ping", func(rw http.ResponseWriter, r *http.Request) {
rw.Write([]byte("pong"))
})
In both cases, I don't get a CORS error.
Hi @muhammadqazi, both examples work for me, the only error a found was when you write the handler using the mux library in the path, you forgot the
/
in the path, it must be/ping
. Maybe was a copy-paste error here, you wrote:// test route r.HandleFunc("ping", func(rw http.ResponseWriter, r *http.Request) { rw.Write([]byte("pong")) })And mus be:
// test route r.HandleFunc("/ping", func(rw http.ResponseWriter, r *http.Request) { rw.Write([]byte("pong")) })In both cases, I don't get a CORS error.
yeah thats a copy/paste mistake, but mux and gin both are not working for me in any case except postman
package main
import (
"context"
"net/http"
"os"
"time"
"github.com/golang-migrate/migrate/v4"
_ "github.com/golang-migrate/migrate/v4/database/postgres"
_ "github.com/golang-migrate/migrate/v4/source/file"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/jackc/pgx/v5/pgxpool"
_ "github.com/mattes/migrate/source/file"
)
func main() {
r := mux.NewRouter()
r.HandleFunc("/ping", func(rw http.ResponseWriter, r *http.Request) {
rw.Write([]byte("pong"))
})
ch := handlers.CORS(handlers.AllowedOrigins([]string{"*"}))
s := http.Server{
Addr: "localhost:9000",
Handler: ch(r),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 120 * time.Second,
}
logger.Info("Server started at port", env.PORT)
err = s.ListenAndServe()
if err != nil {
err = tracerr.Wrap(err)
tracerr.PrintSourceColor(err)
os.Exit(1)
}
}
@muhammadqazi could you also share the React JS request?
@muhammadqazi I created a tiny and silly project of a React app created with Vite, it only has a button that calls the ping endpoint and works fine: test cors gorilla mux it only changes the text of the button, when receiving the pong response.
Inside also is the Go code of the endpoint.
@muhammadqazi was having the same issue, kind of difficult to troubleshoot without seeing your react code. But what worked for me was to set the AllowedOrigins
prefixed with http://*
or https://*
. The preflight check isn't needed.
Also had to set the Content-Type: application/json
manually. But on the react side I use the createApi
function.
@itsdeekay That's my reactjs code, it's not working with the fetch() but i tried in axios now and it worked.
fetch("http://localhost:9000/ping", {
method: "GET",
headers: {
"Content-Type": "application/json"
}
})
.then(response => response.json())
.then(data => {
// Handle the response data
console.log(data);
})
.catch(error => {
// Handle any errors that occurred during the request
console.error("Error:", error);
});
Axios
axios.get("http://localhost:9000/ping").then(response => {
console.log(response);
});
@muhammadqazi I think your error is related to this line .then(response => response.json())
in the fetch without Axios. You are trying to parse the pong response to JSON, also the header is not ok. If you see your code with Axios, you never specified that the response is in JSON format.
You could try something like this:
.then(response => {
console.log(response)
response.json()
})
And see the response before trying to parse it to JSON. If you receive it right there, you need to change your endpoint to return a JSON, or in that fetch use response. text()
javascript doc In the repo I created you can see I use response.text()
You don't see the parse JSON error in the console?
@jackgris Thanks man, it's working, I removed the header and just console the response.