I have created an API using Go. It's working fine in postman but not when consumed using javascript. When I post request using javascript I'm getting an error saying that Access-Control-Allow-Origin is set to null.
go API code:
package main
import (
"fmt"
"encoding/json"
"github.com/gorilla/mux"
"log"
"net/http"
)
type Calculate struct {
Operand1 string `json:"Operand1,omitempty"`
Operand2 string `json:"Operand2,omitempty"`
Operator string `json:"Operator,omitempty"`
}
type Answer struct {
Res string `json:"Res,omitempty"`
}
func do_Calculation(w http.ResponseWriter, r *http.Request) {
var cal Calculate
var ans Answer
fmt.Println("Request Reached")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.WriteHeader(http.StatusOK)
json.NewDecoder(r.Body).Decode(&cal)
// my stuff
// res := do_Operations(convertToFloat(cal.Operand1),convertToFloat(cal.Operand2),cal.Operator)
// ans = Answer{Res: floattostrwithprec(res, 4)}
json.NewEncoder(w).Encode(ans)
}
// main function to boot up everything
func main() {
router := mux.NewRouter()
router.HandleFunc("/calculate", do_Calculation).Methods("POST")
fmt.Println("Server online at port :8000")
log.Fatal(http.ListenAndServe(":8000", router))
}
javascript code:
var data = JSON.stringify({
"Operand1": "2.6",
"Operand2": "2.4",
"Operator": "+"
});
var xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
if (this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("POST", "http://localhost:8000/calculate");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Cache-Control", "no-cache");
xhr.setRequestHeader("Access-Control-Allow-Origin", "*");
xhr.setRequestHeader("Access-Control-Allow-Methods", "POST");
xhr.withCredentials = true;
xhr.send(data);
error:
Failed to load http://127.0.0.1:8000/calculate: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'null' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
Whenever you are setting xhr request with credentials to true. It is a security loop hole to allow cross origin request for all domains using wild card *
. So add http://localhost:8000/
to the Access-Control-Allow-Origin
.
var xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
if (this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("POST", "http://localhost:8000/calculate");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Cache-Control", "no-cache");
xhr.setRequestHeader("Access-Control-Allow-Origin", "http://localhost:8000");
xhr.setRequestHeader("Access-Control-Allow-Methods", "POST");
xhr.withCredentials = true;
xhr.send(data);
Also in header in go lang code allow for http://localhost:8000
:
func do_Calculation(w http.ResponseWriter, r *http.Request) {
var cal Calculate
var ans Answer
fmt.Println("Request Reached")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.Header().Set("Access-Control-Allow-Origin", "http://localhost:8000")
w.WriteHeader(http.StatusOK)
json.NewDecoder(r.Body).Decode(&cal)
// my stuff
// res := do_Operations(convertToFloat(cal.Operand1),convertToFloat(cal.Operand2),cal.Operator)
// ans = Answer{Res: floattostrwithprec(res, 4)}
json.NewEncoder(w).Encode(ans)
}
A preflight request is a request to the server BEFORE the actual GET/POST/PUT/etc. It is of type OPTIONS to check if cross origin is allowed or not. Your server obviously does not implement a OPTIONS call as it says in your javascript error: OPTIONS localhost:8000/calculate 405 (Method Not Allowed)
Since this is an extra request with method OPTIONS it will never arrive in do_Calculation
handler. So you cannot fix the problem there.
What you have to do is register a global handler /
of type OPTIONS and return the correct header information in there.
If you are using gin or gorilla or another router they might have an easy way of setting up such a handler. If you do not use a special router or want to do it manually, check here for what headers are expected by an OPTIONS call.
In Javascript I don't think you have to set any special headers but I wouldn't bet on it. Last time I implemented this I only implemented the go server side.
I used it with gin and simply had to use the following code:
CORSHandler = cors.New(cors.Config{
AllowAllOrigins: true,
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "HEAD"},
AllowHeaders: []string{"Origin", "Content-Length", "Content-Type"},
AllowCredentials: false,
MaxAge: 12 * time.Hour,
})
router.Use(CORSHandler)