How get DATA from frontend in gin?

南楼画角 提交于 2020-06-29 05:26:18

问题


To my shame, I have not been able to figure out how to get data from the frontend in Gin framework. In Django I get data So:

user=request.data.get('user')
print(user)

Everything is simple and understandable as day. How should I do it in gin?

user := c.Query("user")
user := c.Param("user")
user := c.Params.ByName("user")
user := c.PostForm("user")
println(user)//emptiness....

回答1:


Well, I'd say you should fetch some book/HOWTO on how HTTP work and spend some time with it because it appears you're trying to bash the problem at hand without actually understanding what happens between your browser and your backend service.

The real problem here is that there are more moving parts that you appear to be aware of, and the way to go depends on what your frontent does.

You did not tell us exactly how you're doing your request, but from a solicted comment it appears, you're using that "axios" tingy. If I managed to google that project correctly, its README states:

By default, axios serializes JavaScript objects to JSON. To send data in the application/x-www-form-urlencoded format instead, you can use one of the following options.

This means two things:

  1. Unless you somehow tweaked the axios' settings, when you did axios.post, is supposedly performed an HTTP POST request with its Content-Type field set to application/json and its payload (or "body" if you prefer) being a JSON serialization of that {user:this.user} JavaScript object.
  2. It's therefore futile to attempt to parse the query string. And it's futile to attempt to parse the request as an HTTP form — which it isn't.

Instead, you supposedly want to interpret the incoming request's body as being JSON-formatted. I have no idea as to how to do that in "go-gin", but in plain Go that would be something like

func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
  defer req.Body.Close()

  var user User

  dec := json.NewDecoder(req.Body)
  err := dec.Decode(&user)
  if err != nil {
    rw.Header().Set("Content-Type", "text/plain; charset=UTF-8")
    rw.WriteHeader(http.StatusBadRequest)
    fmt.Fprintln(rw, "Error parsing request body: ", err)
    return
  }
}

And ideally you'd first check that the content type of the incoming request was indeed application/json and reject it right away with http.StatusBadRequest if it isn't.

An example of a working code to do that is

// VerifyContentTypeIsJSON makes sure the HTTP header of a server
// http.Request contains the Content-Type field and it indicates
// the request payload is JSON.
// The implementation is based on RFC 7231 (section 3.1.1.5) and RFC 8259.
func VerifyContentTypeIsJSON(header http.Header) error {
    var s string

    if values := header["Content-Type"]; len(values) > 0 {
        s = values[0]
    } else {
        return errors.New("missing Content-Type")
    }

    if s == "" {
        return errors.New("empty Content-Type")
    }

    if i := strings.IndexByte(s, ';'); i != -1 {
        s = strings.TrimSpace(s[:i])
    }

    if strings.ToLower(s) != "application/json" {
        return fmt.Errorf("unknown Content-Type: %v, must be application/json", s)
    }

    return nil
}

Having this function, you'd have something like this after defer req.Body.Close() and actually parsing it:

if err := VerifyContentTypeIsJSON(req.Header); err != nil {
  rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
  rw.WriteHeader(http.StatusBadRequest)
  fmt.Fprintln(rw, err)
  return
}

(Note that "go-gin" might have something akin to this already built-in, so please check this.)

The User type should be some struct type matching the shape of the JSON object you intend to unmarshal from the request. Something like this:

type User struct {
  User string `json:"user"`
}

None that in the two places my example returned an error to the user it used content type of plain text (in UTF-8 encoding). This may be OK but may be not. Say, your clients might expect a JSON-formatted document of some agreed-upon shape.

Or you may use content negotiation, but I'd recommend to get simple things straight first.


Literature to check:

  • HTTP POST request explained at MDN.
  • URL's query string.
  • XHR explained at MDN — see also links there.
  • "Writing Web Applications in Go", and this in general.

And to maybe answer that part of your question regarding why it "just worked" in Django. I can only guess, but I think it merely implements tons of magic which looks at the incoming request and tries to guess how to extract data from it.

The problem is that guessing may indeed work well for one-off throwaway scripts, but when you're about implementing something like web API (what many not quite correctly call "REST", but let's not digress) it's best to be very explicit about what your endpoint accept precisely and how precisely they react to requests — both legitimate and non-well-formed.

Regarding magic in Go, you may read this.




回答2:


you need to call c.Request.ParseForm() before using it from request.Form

says here:

For all requests, ParseForm parses the raw query from the URL and updates r.Form

For other HTTP methods, or when the Content-Type is not application/x-www-form-urlencoded, the request Body is not read, and r.PostForm is initialized to a non-nil, empty value.




回答3:


If you're expecting a JSON body in the request, you can do it this way with gin. Create a struct for the data you want to grab out of the body. Use json tags for the JSON key names unless you're going to exactly match your Go field names to them. Then call the BindJSON method on the gin context.

For example:

type User struct {
    FirstName string `json:"first_name"`
    LastName  string `json:"last_name"`
    Login     string `json:"login"`
}

func (h *Handler) HandleUser(gctx *gin.Context) {
    user := new(User)
    err := gctx.BindJSON(user)
    if err != nil {
        text := fmt.Sprintf("Failed to read user data from request: %s", err)
        log.Error(text)
        gctx.JSON(http.StatusBadRequest, gin.H{"error": text})
        return
    }
    // do something with user
}



回答4:


Server GIN can't handle routine default application/json requests from axios!!! What??? Requests should be sent as application/x-www-form-urlencoded. My decision in Vue project: Use vue-resource instead axios (axios.post=>this.$http.post) with option Vue.http.options.emulateJSON = true; in main.js



来源:https://stackoverflow.com/questions/53240259/how-get-data-from-frontend-in-gin

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!