I have added this code in my service but the server is not sending Access-Control headers, am I doing something wrong, I've attached a screenshot of all the response headers I'm getting.
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Content-Type", "application/json")
c.Writer.Header().Set("Access-Control-Allow-Methods", "PATCH, PUT, POST, GET, DELETE, OPTIONS")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Access-Control-Allow-Headers, X-Custom-Header, Content-Type, Content-Template, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
log.Infof(c, "All headers %v", c.Writer.Header())
log.Infof(c, "All headers %v", c.Request.Header)
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
return
}
c.Next()
}
}
router := gin.Default()
router.Use(gin.Recovery())
router.Use(middlewares.CORSMiddleware())
router.Use(middlewares.AuthMiddleware())
How can I solve this issue, one more thing, the response status code is 301 and the method type is OPTIONS, I don't know why this is happening.
Related
I have a React app using fetch calling to a go mux api.
I am well aware of the question here: Making golang Gorilla CORS handler work
but this does not work for me. I have tried everything in that post and still no success. Looks like go is not even running any middleware or route handler function for me.
Here is the first way I tried fixing it. This uses gorilla/handlers
package main
import (
"fmt"
"net/http"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
)
func commonMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println("MIDDLEWARE CALLED")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
next.ServeHTTP(w, r)
})
}
func ApiHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("ROUTE CALLED")
fmt.Fprintf(w, `{"works:"true}`)
}
func main() {
var router *mux.Router = mux.NewRouter()
router.Use(commonMiddleware)
router.HandleFunc("/api", ApiHandler).Methods("POST")
headersOk := handlers.AllowedHeaders([]string{"Access-Control-Allow-Origin", "Accept", "Accept-Language", "Content-Type", "Content-Language", "Origin"})
originsOk := handlers.AllowedOrigins([]string{"http://localhost:*", "*"})
methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"})
http.ListenAndServe(":8000", handlers.CORS(headersOk, originsOk, methodsOk)(router))
}
This uses rs/cors
package main
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
"github.com/rs/cors"
)
func commonMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println("MIDDLEWARE CALLED")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
next.ServeHTTP(w, r)
})
}
func ApiHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("ROUTE CALLED")
fmt.Fprintf(w, `{"works:"true}`)
}
func main() {
var router *mux.Router = mux.NewRouter()
router.Use(commonMiddleware)
router.HandleFunc("/api", ApiHandler).Methods("POST")
c := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
AllowCredentials: true,
})
handler := c.Handler(router)
http.ListenAndServe(":8000", handler)
}
However, in both cases CORS errors still appear in the browser. I am running the react server on port 5000 and the go server is on port 8000.
fetch("http://localhost:8000/api", {
method: 'POST',
headers: {
// "Access-Control-Allow-Origin": "*",
'Content-Type': 'application/json'
},
body: JSON.stringify({
example: 1
})
})
Error in Chrome:
Access to fetch at 'http://localhost:8000/validate/' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Neither solution works. In fact "MIDDLEWARE CALLED" and "ROUTE CALLED" in go never print out. The api works just fine in Postman so I know the router works fine and the issue really is CORS. So it appears that the route never gets called.
This is stunning, could it have something to do with preflight. How do I disable all cors issues?
If you want to allow all origin, the other way you can do it is
c := cors.New(cors.Options{
AllowOriginFunc: func(r string) bool {
return true
}
})
I had a similar problem. The issue was in my antivirus software. Disabiling it fixed the issue.
I made a backend in go and deployed it using Google Cloud Run. Now I am trying to ping it from my website hosted locally, but then I get a CORS error like
type: "cors"
url: "https://abc.a.run.app/do-a"
redirected: false
status: 500
ok: false
statusText: ""
headers: Headers {}
body: (...)
bodyUsed: false
These are the headers I set in my http handler function in go.
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "http://localhost:3000")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
My handler function is routed like
func main() {
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
http.HandleFunc("/do-a", endpoints.DoA)
err := http.ListenAndServe(":"+port, nil)
handle(err)
}
Please check this example from the official documentation:
// Package http provides a set of HTTP Cloud Functions samples.
package http
import (
"fmt"
"net/http"
)
// CORSEnabledFunctionAuth is an example of setting CORS headers with
// authentication enabled.
// For more information about CORS and CORS preflight requests, see
// https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request.
func CORSEnabledFunctionAuth(w http.ResponseWriter, r *http.Request) {
// Set CORS headers for the preflight request
if r.Method == http.MethodOptions {
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Header().Set("Access-Control-Allow-Headers", "Authorization")
w.Header().Set("Access-Control-Allow-Methods", "POST")
w.Header().Set("Access-Control-Allow-Origin", "https://example.com")
w.Header().Set("Access-Control-Max-Age", "3600")
w.WriteHeader(http.StatusNoContent)
return
}
// Set CORS headers for the main request.
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Header().Set("Access-Control-Allow-Origin", "https://example.com")
fmt.Fprint(w, "Hello World!")
}
From the code you posted I can not tell if you check for the preflight request and set the Access-Control-Allow-Methods header.
I'm implementing REST API's in Go and for that I want to allow cross origin requests to be served.
What I am currently doing:
Go server code:
//handleCrossO ... This function will handle CROS
func handleCrossO(w *http.ResponseWriter) {
(*w).Header().Set("Content-Type", "application/json")
(*w).Header().Set("Access-Control-Allow-Origin", "*")
(*w).Header().Set("Access-Control-Allow-Methods", "POST, GET,
OPTIONS, PUT, DELETE")
(*w).Header().Set("Access-Control-Allow-Headers", "Accept,
Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token,
Authorization, Auth")
}
//Response ... This function will create response
func Response(w http.ResponseWriter, message string, statusCode int)
{
handleCrossO(&w)
w.WriteHeader(statusCode)
w.Write([]byte("{\"message\":\"" + message + "\"}"))
}
I am getting the following error on browser console:
Access to XMLHttpRequest at 'http://ip:8080/config' from origin 'http://ip:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I have also tried the following code to check OPTIONS method:
// CheckAuthorization function check if the User is autrhorized to make calls or not
// if ssid is mising then give unauthorized error otherwise call next
func CheckAuthorization(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.Method == "OPTIONS" {
//handle preflight in here
response.Response(w, "success", 200)
}else {
store := session.SessionStore()
session, _ := store.Get(r, utils.SessionName)
ssid := r.Header.Get("Auth")
if _, ok := session.Values[ssid]; ok {
next.ServeHTTP(w, r)
} else {
var getTokenRes = GetTokenRes{}
sendResponse(w, getTokenRes, 1, "Invalid
SSID", 400)
}
}
}
}
But it is not working.
I have also tried allow OPTIONS method:
router.HandleFunc("/network", authmiddleware.CheckAuthorization(createConfiguration)).Methods("POST", "OPTIONS")
Preflight request should return success and headers. Try to use like following
func setupResponse(w *http.ResponseWriter, req *http.Request) {
(*w).Header().Set("Access-Control-Allow-Origin", "*")
(*w).Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
(*w).Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
}
func indexHandler(w http.ResponseWriter, req *http.Request) {
setupResponse(&w, req)
if (*req).Method == "OPTIONS" {
return
}
// process the request...
}
Also you can use https://github.com/rs/cors
package main
import (
"net/http"
"github.com/rs/cors"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte("{\"hello\": \"world\"}"))
})
// cors.Default() setup the middleware with default options being
// all origins accepted with simple methods (GET, POST). See
// documentation below for more options.
handler := cors.Default().Handler(mux)
http.ListenAndServe(":8080", handler)
}
I'm using Go gin framework gin
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Writer.Header().Set("Content-Type", "application/json")
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Max-Age", "86400")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, X-Max")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(200)
} else {
c.Next()
}
}
}
I've got Status Code:200 OK, but nothing happens after OPTIONS request.
It looks like I miss something, but I can't understand where am I wrong.
Can anybody help me?
FWIW, this is my CORS Middleware that works for my needs.
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
}
There is also official gin's middleware for handling CORS requests github.com/gin-contrib/cors.
You could install it using $ go get github.com/gin-contrib/cors and then add this middleware in your application like this:
package main
import (
"time"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
// CORS for https://foo.com and https://github.com origins, allowing:
// - PUT and PATCH methods
// - Origin header
// - Credentials share
// - Preflight requests cached for 12 hours
router.Use(cors.New(cors.Config{
AllowOrigins: []string{"https://foo.com"},
AllowMethods: []string{"PUT", "PATCH"},
AllowHeaders: []string{"Origin"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
AllowOriginFunc: func(origin string) bool {
return origin == "https://github.com"
},
MaxAge: 12 * time.Hour,
}))
router.Run()
}
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Credentials", "true")
c.Header("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
c.Header("Access-Control-Allow-Methods", "POST,HEAD,PATCH, OPTIONS, GET, PUT")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
}
then use it
router = gin.New()
router.Use(CORSMiddleware())
I spent like an hour to get why some example from the internet works, and some doesn't. So I got the difference - line order is important, fristly you should use config and then declare your endpoints, but not the opposite way.
Works:
router := gin.Default()
router.Use(cors.Default())
router.GET("/ping", pong)
router.Run(":8082")
Doesn't work:
router := gin.Default()
router.GET("/ping", pong)
router.Use(cors.Default())
router.Run(":8082")
There is package https://github.com/rs/cors, that handles CORS requests in the right way. It has the examples for the popular routers including gin. That it:
package main
import (
"net/http"
"github.com/gin-gonic/gin"
cors "github.com/rs/cors/wrapper/gin"
)
func main() {
router := gin.Default()
router.Use(cors.Default())
router.GET("/", func(context *gin.Context) {
context.JSON(http.StatusOK, gin.H{"hello": "world"})
})
router.Run(":8080")
}
In common case, you just add the default handling with router.Use(cors.Default()) to your middlewares in gin. It is enough.
We created a minimal middleware.
import (
"github.com/gin-gonic/gin"
"net/http"
)
type optionsMiddleware struct {
}
func CreateOptionsMiddleware() *optionsMiddleware{
return &optionsMiddleware{}
}
func (middleware *optionsMiddleware)Response(context *gin.Context){
if context.Request.Method == "OPTIONS" {
context.AbortWithStatus(http.StatusNoContent)
}
}
and register it with gin middleware :
app := gin.New()
app.Use(middleware.CreateOptionsMiddleware().Response).
Use(next-middleware)......
This worked for me - NOTE: the setting of header directly.
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Headers", "*")
/*
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
c.Writer.Header().Set("Access-Control-Allow-Headers", "access-control-allow-origin, access-control-allow-headers")
c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH")
*/
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
}
With gin-contrib/cors
import "github.com/gin-contrib/cors"
[...]
router.Use(cors.New(cors.Config{
AllowOrigins: []string{"http://localhost:4040"},
AllowMethods: []string{"GET"},
AllowHeaders: []string{"Content-Type", "Content-Length", "Accept-Encoding", "Authorization", "Cache-Control"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
MaxAge: 12 * time.Hour,
}))
In my case, I had a JWT token middleware before this one that blocked all OPTION pre-flight requests. Putting the CORS middleware first solved the problem.
My frontend was adding a trailing slash to the URL's because of which I was getting CORS, do check for trailing slash.
So I've got this Go http handler that stores some POST content into the datastore and retrieves some other info in response. On the back-end I use:
func handleMessageQueue(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
if r.Method == "POST" {
c := appengine.NewContext(r)
body, _ := ioutil.ReadAll(r.Body)
auth := string(body[:])
r.Body.Close()
q := datastore.NewQuery("Message").Order("-Date")
var msg []Message
key, err := q.GetAll(c, &msg)
if err != nil {
c.Errorf("fetching msg: %v", err)
return
}
w.Header().Set("Content-Type", "application/json")
jsonMsg, err := json.Marshal(msg)
msgstr := string(jsonMsg)
fmt.Fprint(w, msgstr)
return
}
}
In my firefox OS app I use:
var message = "content";
request = new XMLHttpRequest();
request.open('POST', 'http://localhost:8080/msgs', true);
request.onload = function () {
if (request.status >= 200 && request.status < 400) {
// Success!
data = JSON.parse(request.responseText);
console.log(data);
} else {
// We reached our target server, but it returned an error
console.log("server error");
}
};
request.onerror = function () {
// There was a connection error of some sort
console.log("connection error");
};
request.send(message);
The incoming part all works along and such. However, my response is getting blocked. Giving me the following message:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/msgs. This can be fixed by moving the resource to the same domain or enabling CORS.
I tried a lot of other things but there is no way I can just get a response from the server. However when I change my Go POST method into GET and access the page through the browser I get the data that I want so bad. I can't really decide which side goes wrong and why: it might be that Go shouldn't block these kinds of requests, but it also might be that my javascript is illegal.
#Egidius, when creating an XMLHttpRequest, you should use
var xhr = new XMLHttpRequest({mozSystem: true});
What is mozSystem?
mozSystem Boolean: Setting this flag to true allows making cross-site connections without requiring the server to opt-in using CORS. Requires setting mozAnon: true, i.e. this can't be combined with sending cookies or other user credentials. This only works in privileged (reviewed) apps; it does not work on arbitrary webpages loaded in Firefox.
Changes to your Manifest
On your manifest, do not forget to include this line on your permissions:
"permissions": {
"systemXHR" : {},
}
You need other headers, not only access-control-allow-origin.
If your request have the "Access-Control-Allow-Origin" header, you must copy it into the response headers, If doesn't, you must check the "Origin" header and copy it into the response. If your request doesn't have Access-Control-Allow-Origin not Origin headers, you must return "*".
You can read the complete explanation here: http://www.html5rocks.com/en/tutorials/cors/#toc-adding-cors-support-to-the-server
and this is the function I'm using to write cross domain headers:
func writeCrossDomainHeaders(w http.ResponseWriter, req *http.Request) {
// Cross domain headers
if acrh, ok := req.Header["Access-Control-Request-Headers"]; ok {
w.Header().Set("Access-Control-Allow-Headers", acrh[0])
}
w.Header().Set("Access-Control-Allow-Credentials", "True")
if acao, ok := req.Header["Access-Control-Allow-Origin"]; ok {
w.Header().Set("Access-Control-Allow-Origin", acao[0])
} else {
if _, oko := req.Header["Origin"]; oko {
w.Header().Set("Access-Control-Allow-Origin", req.Header["Origin"][0])
} else {
w.Header().Set("Access-Control-Allow-Origin", "*")
}
}
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
w.Header().Set("Connection", "Close")
}
You have to placed this code in application.rb
config.action_dispatch.default_headers = {
'Access-Control-Allow-Origin' => '*',
'Access-Control-Request-Method' => %w{GET POST OPTIONS}.join(",")
}