So I'm trying to use isomorphic-fetch https://www.npmjs.com/package/isomorphic-fetch
I have a server written in go that is giving back JSON data. This is how I'm making the call -
export function fetchDistricts(geoState) {
return function (dispatch) {
dispatch(requestDistricts(geoState));
return fetch(`http://localhost:8100/districts/`)
.then(response => {console.log(response);})
.then(json => {
console.log("json");
});
}
I get this error in the chrome console
Fetch API cannot load http://localhost:8100/districts/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8200' is therefore not allowed access.
This is weird, because in my handler I am doing this
func getDistricts(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/jsonp;charset=UTF-8")
w.WriteHeader(http.StatusOK)
w.Header().Set("Access-Control-Allow-Origin", "*")
rows, err := db.Query("SELECT * from districts")
//other code here
Further, this was working
var activitiesDfD = $.ajax({
url: "http://localhost:8100/district/1/activities",
type: "GET",
dataType: "json"
});
$.when(activitiesDfD).then(function(data, textStatus, jqXhr) {
Why would this fail when using the fetch API and how do I get around this?
Edit-
I've now tried this
func getDistricts(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/jsonp;charset=UTF-8")
w.Header().Set("Access-Control-Allow-Origin", r.Header.Get(`origin`))
w.WriteHeader(http.StatusOK)
Incorporating the two suggestions below - but the error is the same.
Almost all web browsers reject the origin "*". Therefore sending "*" as the Access-Control-Allow-Origin header results in a same-origin-policy violation.
Fortunately there is a work-around. If you look at the gin-cors code that handles this, what it does instead is to re-send the "origin" header sent by the browser. So to make * work, you'd have to do this:
w.Header().Set("Access-Control-Allow-Origin", r.Header.Get(`origin`))
I ended up using this middleware https://github.com/rs/cors, and that got everything working correctly.
Related
I have fairly simple setup here as described in the code below. But I am not able to get the CORS to work. I keep getting this error:
XMLHttpRequest cannot load http://localhost:3000/signup. Response to
preflight request doesn't pass access control check: No 'Access-
Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:8000' is therefore not allowed access. The
response had HTTP status code 403.
I am sure I am missing something simple here.
Here is the code I have:
package main
import (
"log"
"net/http"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"myApp/src/controllers"
)
func main() {
ac := new(controllers.AccountController)
router := mux.NewRouter()
router.HandleFunc("/signup", ac.SignUp).Methods("POST")
router.HandleFunc("/signin", ac.SignIn).Methods("POST")
log.Fatal(http.ListenAndServe(":3000", handlers.CORS()(router)))
}
Please read the link Markus suggested, and also about what triggers CORS pre-flight requests.
Pre-flight requests: You may have a content type like JSON, or some other custom header that's triggering a pre-flight request, which your server may not be handling. Try adding this one, if you're using the ever-common AJAX in your front-end: https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Requested-With
Gorilla's handlers.CORS() will set sane defaults to get the basics of CORS working for you; however, you can (and maybe should) take control in a more functional manner.
Here's some starter code:
// Where ORIGIN_ALLOWED is like `scheme://dns[:port]`, or `*` (insecure)
headersOk := handlers.AllowedHeaders([]string{"X-Requested-With"})
originsOk := handlers.AllowedOrigins([]string{os.Getenv("ORIGIN_ALLOWED")})
methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"})
// start server listen
// with error handling
log.Fatal(http.ListenAndServe(":" + os.Getenv("PORT"), handlers.CORS(originsOk, headersOk, methodsOk)(router)))
You can get more details here: Why doesn’t Postman get a "No 'Access-Control-Allow-Origin' header is present on the requested resource" error when my JavaScript code does? about this issue.
Also try this handler: Go Cors Handler which should solve your issue. I find this much cleaner and easy to resolve the issue.
package main
import (
"log"
"net/http"
"github.com/rs/cors"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"myApp/src/controllers"
)
func main() {
ac := new(controllers.AccountController)
router := mux.NewRouter()
router.HandleFunc("/signup", ac.SignUp).Methods("POST")
router.HandleFunc("/signin", ac.SignIn).Methods("POST")
c := cors.New(cors.Options{
AllowedOrigins: []string{"http://localhost:8000"},
AllowCredentials: true,
})
handler := c.Handler(router)
log.Fatal(http.ListenAndServe(":3000", handler)
}
You should create a CORSOption object. For example to allow any origin, Use this code:
corsObj:=handlers.AllowedOrigins([]string{"*"})
Then you pass this object to your handle.CORS function:
log.Fatal(http.ListenAndServe(":3000", handlers.CORS(corsObj)(router)))
For testing it you can use CURL:
curl -H "Origin: http://example.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: X-Requested-With" \
-X OPTIONS --verbose http://127.0.0.1:3000
When it works you should see those headers:
> Accept: */*
> Origin: http://example.com
> Access-Control-Request-Method: POST
> Access-Control-Request-Headers: X-Requested-With
Final code is here: https://play.golang.org/p/AOrlJsWhvf
More info:
AllowedOrigin function
How can you debug a CORS request with cURL?
I realize this is an old issue but nonetheless it took me 30min to get this right.
handler = handlers.CORS(
// handlers.AllowedMethods([]string{"GET", "POST", "PUT"}),
handlers.AllowedHeaders([]string{"Accept", "Accept-Language", "Content-Type", "Content-Language", "Origin"}),
// handlers.AllowedOrigins([]string{"*"}),
)(handler)
Things to note:
AllowedMethods does NOT need to explicitly include OPTIONS, this is part of the CORS handler
AllowedHeaders need to be explicitly mentioned, * is not a valid wildcard. Typical ajax libraries will send Content-Type when requesting something like application/json, so add that as well.
* is the default for AllowedOrigin
After declaring the mux object, add the accessControlMiddleware as a middleware to the declared object.
func main(){
ac := new(controllers.AccountController)
router := mux.NewRouter()
router.Use(accessControlMiddleware)
router.HandleFunc("/signup", ac.SignUp).Methods("POST")
router.HandleFunc("/signin", ac.SignIn).Methods("POST")
http.ListenAndServe(":3000", corsOpts.Handler(router))
}
// access control and CORS middleware
func accessControlMiddleware(next 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, POST, OPTIONS,PUT")
w.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type")
if r.Method == "OPTIONS" {
return
}
next.ServeHTTP(w, r)
})
}
package main
import (
"log"
"net/http"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"myApp/src/controllers"
"github.com/rs/cors"
)
func main() {
ac := new(controllers.AccountController)
router := mux.NewRouter()
router.HandleFunc("/signup", ac.SignUp).Methods("POST")
router.HandleFunc("/signin", ac.SignIn).Methods("POST")
//cors optionsGoes Below
corsOpts := cors.New(cors.Options{
AllowedOrigins: []string{"http://localhost:8100"}, //you service is available and allowed for this base url
AllowedMethods: []string{
http.MethodGet,//http methods for your app
http.MethodPost,
http.MethodPut,
http.MethodPatch,
http.MethodDelete,
http.MethodOptions,
http.MethodHead,
},
AllowedHeaders: []string{
"*",//or you can your header key values which you are using in your application
},
})
http.ListenAndServe(":3000", corsOpts.Handler(router))
}
Base on jeremiah.trein's answer.
CORS filters are set on server side. Request may work with Postman and fail with a browser because Postman doesn't send preflight request whereas a browser does.
Setting the CORS filters will allow you to configure the origins, methods and headers that the backend shall accept.
In addition, if your browser emits POST or PUT requests that contain a json payload (which is quite reasonnable), you'll need to add 'Content-Type' to the allowed headers.
Finally the handlers.CORS()(router) does not only work with the http.ListenAndServe function but also with http.Handle().
The snippet of code might as well look like:
router := mux.NewRouter()
// do all your routes declaration
headersOK := handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type"})
originsOK := handlers.AllowedOrigins([]string{"*"})
methodsOK := handlers.AllowedMethods([]string{"GET", "POST", "OPTIONS", "DELETE", "PUT"})
http.Handle("/", handlers.CombinedLoggingHandler(os.Stderr, handlers.CORS(headersOK, originsOK, methodsOK)(router)))
It is worth mentionning that i have successfuly used this snippet of code in a Google Cloud Platform Standard AppEngine (and I believe it would work in a Flex AppEngine as well).
The aformentioned package github.com/rs/cors provides a constructor
AllowAll() *Cors
that
...create a new Cors handler with permissive configuration allowing all
origins with all standard methods with any header and credentials.
I'm using LabStack's Golang Echo Framework to build out a service.
One of the routes, needs to proxy requests and responses to and from a backend service.
But I also need CORS to work on this service as well.
So I'm using middleware.CORSWithConfig along w/ a middleware.ProxyWithConfig in my request/response stack.
I'm seeing some oddness w/ the Access-Control-Allow-Origins header where the value for that header on the response from the proxied service to my Echo server *, but once it passes through the proxy, it changes to *, * by the time it gets back into the client.
Upon which I start seeing the following browser errors related to CORS violations:
VM1627:362 Access to XMLHttpRequest at 'http://localhost:6273/' from origin 'http://localhost:8002' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed.
Has anyone come across this? Anyone have any idea why this might be happening and maybe a way around it?
Here's some example code:
package main
func singleTargetBalancer(url *url.URL) middleware.ProxyBalancer {
targetURL := []*middleware.ProxyTarget{
{
URL: url,
},
}
return middleware.NewRoundRobinBalancer(targetURL)
}
func Noop(ctx echo.Context) (err error) {
ctx.String(
http.StatusNotImplemented,
"No op handler should never be reached!",
)
return err
}
func main() {
e := echo.New()
e.HideBanner = true
e.Use(
middleware.CORSWithConfig(middlewares.CustomCorsConfig),
middlewares.ThriftMetrics(),
)
// Have to use a Noop handler since we're not trying to set up a full-on proxy for the backend service. We only want this one route to be proxied.
e.POST(
"/",
handlers.Noop,
middleware.ProxyWithConfig(middleware.ProxyConfig{
Balancer: singleTargetBalancer("[backend service URL]"),
})
)
}
I ultimately solved this by writing a custom Echo middleware to hook into the response before Echo's proxy middleware could send the headers back to the client.
func setResponseACAOHeaderFromRequest (req http.Request, resp echo.Response) {
resp.Header().Set(echo.HeaderAccessControlAllowOrigin,
req.Header.Get(echo.HeaderOrigin))
}
func ACAOHeaderOverwriteMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
return func(ctx echo.Context) error {
ctx.Response().Before(func() {
setResponseACAOHeaderFromRequest(*ctx.Request(), *ctx.Response())
})
return next(ctx)
}
}
Then just put this middleware in e.Use() right before your proxy middleware:
e.POST(
"/",
handlers.Noop,
ACAOHeaderOverwriteMiddleware,
middleware.ProxyWithConfig(middleware.ProxyConfig{
Balancer: singleTargetBalancer("[backend service URL]"),
})
)
Docs for Echo's Request::Before() hook: https://echo.labstack.com/guide/response#before-response
I'm want send to user alert if he type wrong password and return it to page were he type password. I'm making it like this
func sendJSONHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
http.ServeFile(w, r, "template/api/api.html")
} else if r.Method == "POST" {
r.ParseForm()
if r.Form["password"][0] == "apiPassword" {
j := struct {
Proxies []string
}{Proxies: code.UP.Proxy}
w.Header().Set("Access-Control-Allow-Origin", corsAddrSite)
json.NewEncoder(w).Encode(j)
} else {
// here is a problem
fmt.Fprintln(w, "<script>alert('Wrong Password')</script>")
http.ServeFile(w, r, "template/api/api.html")
}
}
}
But i'v get http: multiple response.WriteHeader calls error.
How to do it right?
You cannot write to the http.ResponseWriter more than once depending on the HTTP spec.
from the go docs https://golang.org/pkg/net/http/#ResponseWriter
To solve your issue, you could have the script tags inside the template file, or make a new template. You could also tailor the response by adding the alert script before you send it. Maybe with template files.
However a proper solution to this problem might be to have more logic in the actual html served, the front end should display a response based on the status code or response body.
I have fairly simple setup here as described in the code below. But I am not able to get the CORS to work. I keep getting this error:
XMLHttpRequest cannot load http://localhost:3000/signup. Response to
preflight request doesn't pass access control check: No 'Access-
Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:8000' is therefore not allowed access. The
response had HTTP status code 403.
I am sure I am missing something simple here.
Here is the code I have:
package main
import (
"log"
"net/http"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"myApp/src/controllers"
)
func main() {
ac := new(controllers.AccountController)
router := mux.NewRouter()
router.HandleFunc("/signup", ac.SignUp).Methods("POST")
router.HandleFunc("/signin", ac.SignIn).Methods("POST")
log.Fatal(http.ListenAndServe(":3000", handlers.CORS()(router)))
}
Please read the link Markus suggested, and also about what triggers CORS pre-flight requests.
Pre-flight requests: You may have a content type like JSON, or some other custom header that's triggering a pre-flight request, which your server may not be handling. Try adding this one, if you're using the ever-common AJAX in your front-end: https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Requested-With
Gorilla's handlers.CORS() will set sane defaults to get the basics of CORS working for you; however, you can (and maybe should) take control in a more functional manner.
Here's some starter code:
// Where ORIGIN_ALLOWED is like `scheme://dns[:port]`, or `*` (insecure)
headersOk := handlers.AllowedHeaders([]string{"X-Requested-With"})
originsOk := handlers.AllowedOrigins([]string{os.Getenv("ORIGIN_ALLOWED")})
methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"})
// start server listen
// with error handling
log.Fatal(http.ListenAndServe(":" + os.Getenv("PORT"), handlers.CORS(originsOk, headersOk, methodsOk)(router)))
You can get more details here: Why doesn’t Postman get a "No 'Access-Control-Allow-Origin' header is present on the requested resource" error when my JavaScript code does? about this issue.
Also try this handler: Go Cors Handler which should solve your issue. I find this much cleaner and easy to resolve the issue.
package main
import (
"log"
"net/http"
"github.com/rs/cors"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"myApp/src/controllers"
)
func main() {
ac := new(controllers.AccountController)
router := mux.NewRouter()
router.HandleFunc("/signup", ac.SignUp).Methods("POST")
router.HandleFunc("/signin", ac.SignIn).Methods("POST")
c := cors.New(cors.Options{
AllowedOrigins: []string{"http://localhost:8000"},
AllowCredentials: true,
})
handler := c.Handler(router)
log.Fatal(http.ListenAndServe(":3000", handler)
}
You should create a CORSOption object. For example to allow any origin, Use this code:
corsObj:=handlers.AllowedOrigins([]string{"*"})
Then you pass this object to your handle.CORS function:
log.Fatal(http.ListenAndServe(":3000", handlers.CORS(corsObj)(router)))
For testing it you can use CURL:
curl -H "Origin: http://example.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: X-Requested-With" \
-X OPTIONS --verbose http://127.0.0.1:3000
When it works you should see those headers:
> Accept: */*
> Origin: http://example.com
> Access-Control-Request-Method: POST
> Access-Control-Request-Headers: X-Requested-With
Final code is here: https://play.golang.org/p/AOrlJsWhvf
More info:
AllowedOrigin function
How can you debug a CORS request with cURL?
I realize this is an old issue but nonetheless it took me 30min to get this right.
handler = handlers.CORS(
// handlers.AllowedMethods([]string{"GET", "POST", "PUT"}),
handlers.AllowedHeaders([]string{"Accept", "Accept-Language", "Content-Type", "Content-Language", "Origin"}),
// handlers.AllowedOrigins([]string{"*"}),
)(handler)
Things to note:
AllowedMethods does NOT need to explicitly include OPTIONS, this is part of the CORS handler
AllowedHeaders need to be explicitly mentioned, * is not a valid wildcard. Typical ajax libraries will send Content-Type when requesting something like application/json, so add that as well.
* is the default for AllowedOrigin
After declaring the mux object, add the accessControlMiddleware as a middleware to the declared object.
func main(){
ac := new(controllers.AccountController)
router := mux.NewRouter()
router.Use(accessControlMiddleware)
router.HandleFunc("/signup", ac.SignUp).Methods("POST")
router.HandleFunc("/signin", ac.SignIn).Methods("POST")
http.ListenAndServe(":3000", corsOpts.Handler(router))
}
// access control and CORS middleware
func accessControlMiddleware(next 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, POST, OPTIONS,PUT")
w.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type")
if r.Method == "OPTIONS" {
return
}
next.ServeHTTP(w, r)
})
}
package main
import (
"log"
"net/http"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"myApp/src/controllers"
"github.com/rs/cors"
)
func main() {
ac := new(controllers.AccountController)
router := mux.NewRouter()
router.HandleFunc("/signup", ac.SignUp).Methods("POST")
router.HandleFunc("/signin", ac.SignIn).Methods("POST")
//cors optionsGoes Below
corsOpts := cors.New(cors.Options{
AllowedOrigins: []string{"http://localhost:8100"}, //you service is available and allowed for this base url
AllowedMethods: []string{
http.MethodGet,//http methods for your app
http.MethodPost,
http.MethodPut,
http.MethodPatch,
http.MethodDelete,
http.MethodOptions,
http.MethodHead,
},
AllowedHeaders: []string{
"*",//or you can your header key values which you are using in your application
},
})
http.ListenAndServe(":3000", corsOpts.Handler(router))
}
Base on jeremiah.trein's answer.
CORS filters are set on server side. Request may work with Postman and fail with a browser because Postman doesn't send preflight request whereas a browser does.
Setting the CORS filters will allow you to configure the origins, methods and headers that the backend shall accept.
In addition, if your browser emits POST or PUT requests that contain a json payload (which is quite reasonnable), you'll need to add 'Content-Type' to the allowed headers.
Finally the handlers.CORS()(router) does not only work with the http.ListenAndServe function but also with http.Handle().
The snippet of code might as well look like:
router := mux.NewRouter()
// do all your routes declaration
headersOK := handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type"})
originsOK := handlers.AllowedOrigins([]string{"*"})
methodsOK := handlers.AllowedMethods([]string{"GET", "POST", "OPTIONS", "DELETE", "PUT"})
http.Handle("/", handlers.CombinedLoggingHandler(os.Stderr, handlers.CORS(headersOK, originsOK, methodsOK)(router)))
It is worth mentionning that i have successfuly used this snippet of code in a Google Cloud Platform Standard AppEngine (and I believe it would work in a Flex AppEngine as well).
The aformentioned package github.com/rs/cors provides a constructor
AllowAll() *Cors
that
...create a new Cors handler with permissive configuration allowing all
origins with all standard methods with any header and credentials.
Need to accept OPTIONS method coming from mobile device,
attempted multiple ways to do so and getting strange behavior:
when trying this I get 403 from the client:
(client sends OPTIONS before POST)
import (
"net/http"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
r.HandleFunc("/users", UserEndpoint)
r.HandleFunc("/projects", ProjectEndpoint)
methods := handlers.AllowedMethods([]string{"OPTIONS", "DELETE", "GET", "HEAD", "POST"}
http.ListenAndServe(":8000", handlers.CORS(methods)(r))
}
if I omit the methods:
http.ListenAndServe(":8000", handlers.CORS()(r))
I get 403 not authorized
Also played around with it, removed the GET method:
methods := handlers.AllowedMethods([]string{"OPTIONS"}
http.ListenAndServe(":8000", handlers.CORS(methods)(r))
but still could
get a 200 GET when tried from rest client in browser (chromes DHC)
but if I remove the OPTIONS:
methods := handlers.AllowedMethods([]string{"DELETE", "GET", "HEAD", "POST"}
http.ListenAndServe(":8000", handlers.CORS(methods)(r))
I get 405
First example is based on gorilla handler docs
Any ideas on this issues?
Thanks
You really need to understand the request being made, but I had a similar problem and resolved it with:
handlers.CORS(
handlers.AllowedOrigins([]string{"*"}),
handlers.AllowedMethods([]string{"POST"}),
handlers.AllowedHeaders([]string{"Content-Type", "X-Requested-With"}),
)(router)
The request I needed to make (which mimics a preflight) was:
curl -H "Origin: http://example.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: X-Requested-With" \
-X OPTIONS --verbose http://127.0.0.1:8080/products
It was really the AllowedHeaders func that made all the difference. As soon as I added that, the 403 error disappeared.
If you look at cors.go Options are specially handled:
corsOptionMethod string = "OPTIONS"
...
if r.Method == corsOptionMethod {
if ch.ignoreOptions {
ch.h.ServeHTTP(w, r)
return
}
if _, ok := r.Header[corsRequestMethodHeader]; !ok {
w.WriteHeader(http.StatusBadRequest)
return
}
method := r.Header.Get(corsRequestMethodHeader)
if !ch.isMatch(method, ch.allowedMethods) {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
...
So 405 is http.StatusMethodNotAllowed, so maybe it is not CORs request header?
There is also an IngoreOptions method for handling Options independely: http://www.gorillatoolkit.org/pkg/handlers#IgnoreOptions - maybe that will work in your case and you can just ignore it, or process Options on your own.