我在网上找不到任何有用的东西。
我正在编写REST API,我想记录请求主体的大小(以字节为单位)作为指标。 Go net / http API不直接提供该功能。 http.Request确实具有Content-Length字段,但是该字段可以为空,否则客户端可能会发送错误的数据。
是否有一种方法可以在中间件级别获得它?暴力破解方法是读取全身并检查大小。但是,如果我在中间件中执行此操作,则处理程序将无法访问主体,因为它已被读取并关闭。
答案 0 :(得分:4)
您可以编写一个自定义ReadCloser
来代理现有的type LengthReader struct {
Source io.ReadCloser
Length int
}
func (r *LengthReader) Read(b []byte) (int, error) {
n, err := r.Source.Read(b)
r.Length += n
return n, err
}
func (r *LengthReader) Close() error {
var buf [32]byte
var n int
var err error
for err == nil {
n, err = r.Source.Read(buf[:])
r.Length += n
}
closeerr := r.Source.Close()
if err != nil && err != io.EOF {
return err
}
return closeerr
}
并对其进行计数。像这样:
{{1}}
这将在您从流中读取字节时对其进行计数,并且在关闭时将首先消耗并计数所有剩余的未读取字节。完成流后,即可访问长度。
答案 1 :(得分:1)
为什么要在这里中间?
简单的方法是b, err = io.Copy(anyWriterOrMultiwriter, r.Body)
b
是err == nil
时请求的总内容长度
根据需要使用请求正文。也b, err = io.Copy(ioutil.Discard, r.Body)
答案 2 :(得分:0)
您可以只读取主体,计算大小,然后将其解组为struct,这样它就会变成:
b, _ := ioutil.ReadAll(r.Body)
size := len(b) // can be nil so check err in your app
if err := json.Unmarshal(b, &input); err != nil {
s.BadReq(w, errors.New("error reading body"))
return
}