背景
线上有个中间件开发需求,需要对请求内容进行部分过滤。由于默认http.Request.Body类型为io.ReadCloser
类型,即只能读一次,读完后直接close掉,后续流程无法继续读取。这对于在http handler之前需要对body进行处理就带来了麻烦。实际上针对这种需求,其他框架有自己的解决方案。 在beego中开启 beego.BConfig.CopyRequestBody = true
后,Controller对应gin的Context中即包含了request.body的拷贝值,可以直接在中间件和Handler中传递。
但是Gin实际上并未提供该功能,issue中的GetRawBody本质也未能解决这个问题。
最后在stackoverflow找到问题解决方案,在这里做个记录,how-to-get-the-json-from-the-body-of-a-request-on-go
> ps:该解决方案同样适用于http原生路由http.ServeMux处理方法。
解决方案
解决思路: 由于 Request.Body 为公共变量,我们在对原有的buffer读取完成后,只要手动创建一个新的buffer然后以同样接口形式替换掉原有的Request.Body即可。
GIN 已经实现:
var body interface{}
if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil {
log.Default().Error("should bind body error", zap.Error(err))
}
bodyStr, _ := json.MarshalToString(body)