内容长度(以Golang计)

时间:2018-11-20 22:32:07

标签: http go

我在网上找不到任何有用的东西。

我正在编写REST API,我想记录请求主体的大小(以字节为单位)作为指标。 Go net / http API不直接提供该功能。 http.Request确实具有Content-Length字段,但是该字段可以为空,否则客户端可能会发送错误的数据。

是否有一种方法可以在中间件级别获得它?暴力破解方法是读取全身并检查大小。但是,如果我在中间件中执行此操作,则处理程序将无法访问主体,因为它已被读取并关闭。

3 个答案:

答案 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)
berr == 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
    }