如何从杜松子酒的前端获取数据?

How get DATA from frontend in gin?

遗憾的是,我一直无法弄清楚如何在 Gin 框架中从前端获取数据。在 Django 中我得到数据所以:

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

一切都像白天一样简单易懂。 我应该如何在杜松子酒中做到这一点?

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

在从 request.Form

使用它之前,您需要先调用 c.Request.ParseForm()

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.

好吧,我想说你应该获取一些 book/HOWTO 有关 HTTP 工作原理的知识,并花一些时间研究它,因为看起来你试图 bash 解决手头的问题,但并未真正理解您的浏览器和后端服务之间发生了什么。

这里真正的问题是你似乎意识到了更多的活动部分,要走的路取决于你的前端做什么。

您没有确切地告诉我们您是如何执行您的请求的, 但是从征求的评论来看,您正在使用 "axios" 小东西。 如果我设法 google 正确地完成了该项目, 它的自述文件 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.

这意味着两件事:

  1. 除非你以某种方式调整了 axios 的设置,否则 axios.post,应该执行 HTTP POST 请求 其 Content-Type 字段设置为 application/json 它的有效载荷(或者 "body" 如果你愿意的话)是 该 {user:this.user} JavaScript 对象的 JSON 序列化。
  2. 因此,尝试解析查询字符串是徒劳的。 尝试将请求解析为 HTTP 表单是徒劳的——事实并非如此。

相反,您应该将传入请求的正文解释为 JSON 格式。我不知道如何在 "go-gin" 中做到这一点,但在普通的 Go 中会像

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
  }
}

理想情况下,您首先检查传入请求的内容类型是否确实是 application/json,如果不是,则立即使用 http.StatusBadRequest 拒绝它。

执行此操作的工作代码示例是

// 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
}

有了这个功能,你就会有这样的东西 在 defer req.Body.Close() 之后实际解析它:

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
}

(请注意,"go-gin" 可能已经内置了与此类似的内容,因此请检查此内容。)

User 类型应该是某种 struct 类型,与您打算从请求中解组的 JSON 对象的形状相匹配。像这样:

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

None 我的示例在两个地方返回了一个 用户错误,它使用了纯文本的内容类型 (采用 UTF-8 编码)。这可能没问题,但也可能不是。 比方说,您的客户可能期望 JSON 格式的文档 一些商定的形状。

或者你可以使用 content negotiation,但我建议先把简单的事情弄清楚。


要检查的文献:


也许可以回答你关于 为什么它在 Django 中 "just worked"。 我只能猜测,但我认为它只是实现了大量的魔法,它会查看传入的请求并尝试猜测如何从中提取数据。

问题是猜测可能确实适用于 一次性脚本,但是当你要实现类似 web API 的东西时(很多人不太正确地称呼 "REST",但我们不要离题)最好 非常明确地说明您的端点接受什么 准确地以及他们如何准确地对请求做出反应——包括合法的和格式不正确的。

关于围棋的魔法,你可以看看this

如果您希望请求中有一个 JSON 正文,您可以使用 gin 以这种方式进行。为要从正文中获取的数据创建一个结构。将 json 标签用于 JSON 键名,除非您要将 Go 字段名与它们完全匹配。然后在 gin 上下文中调用 BindJSON 方法。

例如:

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
}

服务器 GIN 无法处理来自 axios 的例程默认 application/json 请求!!!什么??? 请求应作为 application/x-www-form-urlencoded 发送。 我在 Vue 项目中的决定: 使用 vue-resource 而不是带有选项的 axios (axios.post=>this.$http.post) Vue.http.options.emulateJSON = 真;在 main.js