http.Request r.FormValue ничего не возвращает/карта[]

У меня есть следующий код Go:

package main

import (
  "encoding/json"
  "fmt"
  "github.com/gorilla/mux"
  "github.com/gorilla/handlers"
  "log"
  "net/http"
  "io/ioutil"
)

type rLog struct {
  Method string
  URI string
  FormParam string
}

func commonMiddleware(next http.Handler) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.Header().Add("Content-Type", "application/json")
    formBs, err := ioutil.ReadAll(r.Body)
    if err != nil {
      log.Fatalf("Failed to decode postFormByteSlice: %v", err)
    }
    rl := rLog{Method: r.Method, URI: r.RequestURI, FormParam: string(formBs)}
    log.Printf("%+v", rl)
    next.ServeHTTP(w, r)
  })
}

func main() {
  port := ":3000"
  var router = mux.NewRouter()
  router.Use(commonMiddleware)
  router.HandleFunc("/m/{msg}", handleMessage).Methods("GET")
  router.HandleFunc("/n/", handleNumber).Methods("POST")

  headersOk := handlers.AllowedHeaders([]string{"Authorization"})
  originsOk := handlers.AllowedOrigins([]string{"*"})
  methodsOk := handlers.AllowedMethods([]string{"GET", "POST", "OPTIONS"})

  fmt.Printf("Server is running at http://localhost%s\n", port)
  log.Fatal(http.ListenAndServe(port, handlers.CORS(originsOk, headersOk, methodsOk)(router)))
}

func handleMessage(w http.ResponseWriter, r *http.Request) {
  vars := mux.Vars(r)
  message := vars["msg"]
  response := map[string]string{"message": message}
  json.NewEncoder(w).Encode(response)
}

func handleNumber(w http.ResponseWriter, r *http.Request) {
  log.Println(r.FormValue("name")) // this returns nothing
  response := map[string]string{"name": "1"} // dummy response
  json.NewEncoder(w).Encode(response)
}

То, что я пытаюсь сделать здесь, очень просто.

  1. Я хочу регистрировать все данные формы POST (это делается внутри commonMiddleware)
  2. Получите доступ к данным формы внутри handleNumber т.е. name (и многие другие позже) и выполните с ними некоторую логику.

Проблема, которая у меня есть прямо сейчас, заключается в том, что log.Println(r.FormValue("name")) ничего не возвращает, и мне действительно интересно, почему это произошло.

введите здесь описание изображения

Я пытался добавить r.ParseForm() перед log.Println(r.FormValue("name")). Но это не сработало.

И когда я добавляю строку log.Println(r.Form), она возвращает map[].

Что я здесь пропустил?


person Zulhilmi Zainudin    schedule 21.07.2018    source источник
comment
Использовали ли вы отладчик Go для проверки содержимого r, когда управление входит в вашу функцию commonMiddleware?   -  person Dai    schedule 22.07.2018


Ответы (1)


Вы пытаетесь прочитать r.Body дважды, сначала в commonMiddleware с ioutil.ReadAll(r.Body), а затем в handleNumber с r.ParseForm(). Вы не можете. Это io.Reader, два раза не прочитаешь. Вместо этого вы можете, например, r.ParseForm() в средней одежде, а затем использовать проанализированные данные формы. В middlewear r.PosrForm.Encode() для регистрации, а в обработчике r.FormValue() или r.Form.Get() для извлечения. Я думаю, что-то вроде этого должно быть сделано

func commonMiddleware(next http.Handler) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.Header().Add("Content-Type", "application/json")
    err:=r.ParseForm() //parse in middleware, data will be contained in r.PostForm
    if err != nil {
      log.Fatalf("Failed to decode postFormByteSlice: %v", err)
    }
    rl := rLog{Method: r.Method, URI: r.RequestURI, FormParam: r.PostForm.Encode()} //url.Values.Encode() stringifys form data
    log.Printf("%+v", rl)
    next.ServeHTTP(w, r)
  })
}

func main() {
  port := ":3000"
  var router = mux.NewRouter()
  router.Use(commonMiddleware)
  router.HandleFunc("/m/{msg}", handleMessage).Methods("GET")
  router.HandleFunc("/n/", handleNumber).Methods("POST")
}

func handleNumber(w http.ResponseWriter, r *http.Request) {
  log.Println(r.PostForm.Get("name")) // or just r.Form.Get("name") or r.FormValue("name")
  response := map[string]string{"name": "1"} // dummy response
  json.NewEncoder(w).Encode(response)
}
person Uvelichitel    schedule 21.07.2018
comment
Я очень ценю, если вы можете показать это мне в виде кода. - person Zulhilmi Zainudin; 22.07.2018
comment
r.PostForm.Get() и r.Form.Get() не будут работать в вашем примере, если вы не вызовете r.ParseMultipartForm() или r.ParseForm() перед ними - person vladkras; 08.04.2021