rest - 如何从 fetch 向我的 go API 发出 PUT 请求?

标签 rest reactjs go gorilla

我正在使用 Go(使用 Gorilla mux)创建一个 REST API,并使用 React 创建一个前端应用程序。 GET 请求工作正常,但我无法让 PUT 请求正常工作。它使 OPTIONS 预检请求成功,但从未使 PUT 请求成功。我可能在后端处理不当或请求不正确。我创建了一个将添加 CORS header 的中间件,因为 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)
      )
  }
}

最佳答案

万一其他人遇到类似的问题,我可以通过将 JSON header 添加到我的 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)
      )
  }
}

关于rest - 如何从 fetch 向我的 go API 发出 PUT 请求?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39597109/

相关文章:

c# - 为 REST 服务异步返回 http 状态码 202?

javascript - 无法使用 axios 设置状态

go - 返回void函数并返回另一个void函数的结果?

javascript - 如何在 React 中删除包含子组件的功能性内存组件的渲染器?

Go 的 sync.WaitGroup 丢失了其中一个响应

go - Go 中 bigint.pow(a) 的等价物是什么?

ruby-on-rails - 使用 Cucumber 进行压力测试

rest - 在网页中呈现 ActivePivot

python - Django 休息框架 : Correct way to serialize ListFields

javascript - 有条件的 Redux reducer 使用