我正在使用Go(使用Gorilla mux)和使用React的前端应用程序创建REST API。 GET请求工作正常,但我无法让PUT请求正常工作。它成功地使OPTIONS预检请求成功,但绝不是PUT请求。我可能在后端错误地处理它或者错误地提出请求。我创建了一个中间件,它将添加CORS头,因为gorilla工具包的CORS处理程序根本不允许OPTIONS请求。我也尝试过使用axios而不是fetch来确保它不是我在请求中做错了。我用axios得到了完全相同的行为。
这是路由器:
var V1URLBase string = "/api/v1"
func Load() http.Handler {
r := mux.NewRouter().StrictSlash(true)
// Status endpoints
s := r.PathPrefix(fmt.Sprintf("%s%s", V1URLBase, "/statuses")).Subrouter()
s.HandleFunc("/", handlers.GetStatuses).
Methods("GET")
s.HandleFunc("/{status_id}/", handlers.GetStatus).
Methods("GET")
s.HandleFunc("/", handlers.PostStatus).
Methods("POST")
s.HandleFunc("/{status_id}/", handlers.PutStatus).
Methods("PUT")
s.HandleFunc("/{status_id}/", handlers.DeleteStatus).
Methods("DELETE")
// Visit endpoints
v := r.PathPrefix(fmt.Sprintf("%s%s", V1URLBase, "/visits")).Subrouter()
v.HandleFunc("/", handlers.GetVisits).
Methods("GET")
v.HandleFunc("/{visit_id}/", handlers.GetVisit).
Methods("GET")
v.HandleFunc("/", handlers.PostVisit).
Methods("POST")
v.HandleFunc("/{visit_id}/", handlers.PutVisit).
Methods("PUT")
v.HandleFunc("/{visit_id}/", handlers.DeleteVisit).
Methods("DELETE")
// Member endpoints
m := r.PathPrefix(fmt.Sprintf("%s%s", V1URLBase, "/members")).Subrouter()
m.HandleFunc("/", handlers.GetMembers).
Methods("GET")
m.HandleFunc("/{member_id}/", handlers.GetMember).
Methods("GET")
m.HandleFunc("/", handlers.PostMember).
Methods("POST")
m.HandleFunc("/{member_id}/", handlers.PutMember).
Methods("PUT")
m.HandleFunc("/{member_id}/", handlers.DeleteMember).
Methods("DELETE")
// GymLocation endpoints
gl := r.PathPrefix(fmt.Sprintf("%s%s", V1URLBase, "/gym_locations")).Subrouter()
gl.HandleFunc("/", handlers.GetGymLocations).
Methods("GET")
gl.HandleFunc("/{gym_location_id}/", handlers.GetGymLocation).
Methods("GET")
gl.HandleFunc("/", handlers.PostGymLocation).
Methods("POST")
gl.HandleFunc("/{gym_location_id}/", handlers.PutGymLocation).
Methods("PUT")
gl.HandleFunc("/{gym_location_id}/", handlers.DeleteGymLocation).
Methods("DELETE")
router := ghandlers.LoggingHandler(os.Stdout, r)
router = handlers.WriteCORSHeaders(r)
return router
}
这是CORS处理程序:
func WriteCORSHeaders(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println("HIT")
w.Header().Set("Access-Control-Allow-Origin", r.Header.Get("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",
)
//w.Header().Set("Access-Control-Allow-Credentials", "true")
if r.Method == "OPTIONS" {
return
}
h.ServeHTTP(w, r)
})
}
这是PUT处理程序:
func PutVisit(w http.ResponseWriter, r *http.Request) {
body, _ := ioutil.ReadAll(r.Body)
r.Body.Close()
visitId, err := strconv.ParseInt(mux.Vars(r)[VisitId], 10, 64)
if err != nil {
WriteJSON(w, http.StatusBadRequest, APIErrorMessage{Message: InvalidVisitId})
return
}
visit := &models.Visit{}
err = json.Unmarshal(body, visit)
if err != nil {
WriteJSON(w, http.StatusBadRequest, APIErrorMessage{Message: err.Error()})
return
}
updated, err := datastore.UpdateVisit(visitId, *visit)
if err != nil {
WriteJSON(w, http.StatusInternalServerError, APIErrorMessage{Message: err.Error()})
return
}
WriteJSON(w, http.StatusOK, updated)
}
func WriteJSON(w http.ResponseWriter, statusCode int, response interface{}) {
encoder := json.NewEncoder(w)
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(statusCode)
encoder.Encode(response)
}
以下是启动服务器的主要内容:
func main() {
r := router.Load()
http.ListenAndServe(":8080", r)
}
以下是我对Reactjs的要求:
export function putVisit(visit) {
return function(dispatch) {
return fetch(`http://localhost:8080/api/v1/visits/${visit.visit_id}/`, {
method: 'PUT',
headers: {
'Accept': 'application/json; charset=UTF-8',
'Content-Type': 'application/json; charset=UTF-8'
},
body: JSON.stringify(visit)
})
.then(response => response.json())
.then(json =>
dispatch(updateVisit(json))
)
.catch(err =>
console.log(err)
)
}
}
答案 0 :(得分:0)
如果其他人遇到类似的问题,我可以通过将JSON标头添加到我的CORS函数(而不是WriteJSON函数)来实现这一点:
func CORS(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.Header().Set("Access-Control-Allow-Origin", r.Header.Get("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",
)
w.Header().Set("Access-Control-Allow-Credentials", "true")
if r.Method == "OPTIONS" {
return
}
h.ServeHTTP(w, r)
})
}
我添加之后,请求仍然无法使用fetch。所以,我再次尝试用axios尝试它并且它有效。以下是使用axios的新请求代码。
export function putVisit(visit) {
return function(dispatch) {
return axios.put(`http://localhost:8080/api/v1/visits/${visit.visit_id}/`, visit)
.then(response =>
dispatch(updateVisit(response.data))
)
.catch(err =>
console.log(err)
)
}
}