前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >GET 请求也能传递 Body 数据

GET 请求也能传递 Body 数据

作者头像
老麦
发布2022-12-24 09:41:41
4.7K0
发布2022-12-24 09:41:41
举报
文章被收录于专栏:Go与云原生Go与云原生

通常而言, GET 请求很少传递 Body 数据, 大多情况下都是放在 url 中, 例如

代码语言:javascript
复制
http://example.com/api?key1=value1&key2=value2

但是这样做,

  1. 可能由于 传递数据过多 导致 URL 过程而被拦截。
  2. 运营商会缓存 URL 地址以达到加速的效果, 而有些参数又不想被缓存。
  3. 等等

虽然, 可以使用 POST 请求代替 GET 请求, 在 Body 中传递数据, 但是这样做可能会破坏 RESTful 风格的 API 格式。

在标准协议中, GET 请求是可以携带 Body 数据的, 这些数据是否被处理, 全看 接收端(后端) 的行为。大多数情况下, 大家都选择放弃。

例如 而 gin-gonic/gin 框架在处理 GET 请求的时候, 就选择忽略了 Body 数据。

gin 在选择默认解释器的时候, 发现如果是 GET 请求, 无论 Content-Type 是什么, 都是使用 表单 Form 解释器。

以下代码基于当前最新的 gin@v1.7.4

gin - binding/binding.go#L90

代码语言:javascript
复制
var (
	JSON          = jsonBinding{}
	XML           = xmlBinding{}
	Form          = formBinding{}
	Query         = queryBinding{}
	FormPost      = formPostBinding{}
	FormMultipart = formMultipartBinding{}
	ProtoBuf      = protobufBinding{}
	MsgPack       = msgpackBinding{}
	YAML          = yamlBinding{}
	Uri           = uriBinding{}
	Header        = headerBinding{}
)


// Default returns the appropriate Binding instance based on the HTTP method
// and the content type.
func Default(method, contentType string) Binding {
  // 如果是是 GET 请求, 直接使用 Form 表单方式处理数据
	if method == http.MethodGet {
		return Form
	}
	switch contentType {
	case MIMEJSON:
		return JSON
	case MIMEXML, MIMEXML2:
		return XML
  // ...
  }
}

gin - binding/form.go#L21

代码语言:javascript
复制
func (formPostBinding) Bind(req *http.Request, obj interface{}) error {
  // 获取表单数据的时候, 使用 net/http 库的 req.ParseForm() 方法
	if err := req.ParseForm(); err != nil {
		return err
	}
	if err := mapForm(obj, req.PostForm); err != nil {
		return err
	}
	return validate(obj)
}

在 golang 中默认的 net/http 库, 在处理 表单 form 数据的时候, 特定的 请求方法 GET/DELETE 就选择忽略 body 数据

golang(v1.16.5) , 代码如下

net/http request.go#L1251

代码语言:javascript
复制
// ParseForm populates r.Form and r.PostForm.
//
// For all requests, ParseForm parses the raw query from the URL and updates
// r.Form.
//
// For POST, PUT, and PATCH requests, it also reads the request body, parses it
// as a form and puts the results into both r.PostForm and r.Form. Request body
// parameters take precedence over URL query string values in r.Form.
//
// If the request Body's size has not already been limited by MaxBytesReader,
// the size is capped at 10MB.
//
// 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.
//
// ParseMultipartForm calls ParseForm automatically.
// ParseForm is idempotent.
func (r *Request) ParseForm() error {
	var err error
	if r.PostForm == nil {
    // 三个特定的请求方法, 选择读取 Body
		if r.Method == "POST" || r.Method == "PUT" || r.Method == "PATCH" {
			r.PostForm, err = parsePostForm(r)
		}
    // 其他方法, 选择从 URL 中获取。
		if r.PostForm == nil {
			r.PostForm = make(url.Values)
		}
	}
// ...

ginbinder v0.1.1

ginbinder 是对 gin 绑定数据方法的一个扩展库。

v0.1.1 的发布, 就实现了处理 GET 能获取 Body 数据的想法。

不过为了不违背 gin 和 golang net/http 原本的初衷, 在实现方式上有一个强制要求。即对 body 结构体必须使用 mime tag 指定解释器。

代码语言:javascript
复制
type Params struct {
	Name          string `uri:"name"`
	Age           int    `query:"age,default=18"`
	Money         int32  `query:"money" binding:"required"`
	Authorization string `cookie:"Authorization"`
	UserAgent     string `header:"User-Agent"`
	Data          struct {
		Replicas *int32 `json:"replicas"`
	} `body:"" mime:"json"`  // 通过 mime 强制指定 json 解释器
}

除了 json 解释器之外, mime 还支持 yaml, xml 两种解释器。

代码语言:javascript
复制

// MimeBinding returns the appropriate Binding instance based on mime value in body tag
func MimeBinding(mime string) Binding {
	switch mime {
	case "json":
		return JSON
	case "xml":
		return XML
	case "yaml", "yml":
		return YAML
	}
	return nil
}

详细用法和demo, 可以查看 https://github.com/tangx/ginbinder

或者查看之前的文章 ginbinder 一次绑定 gin request 中的所有需要的数据

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-09-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 熊猫云原生Go 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ginbinder v0.1.1
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档