猿问

Golang 中的内容长度

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

我正在编写一个 REST API,我想以字节为单位记录请求正文的大小以获取指标。Go net/http API 不直接提供。http.Request 确实有 Content-Length 字段,但该字段可以为空,否则客户端可能会发送虚假数据。

有没有办法在中间件级别获得它?蛮力方法是阅读全身并检查大小。但是如果我在中间件中这样做,处理程序将无法访问主体,因为它已经被读取和关闭。


慕妹3146593
浏览 177回答 3
3回答

Qyouu

你为什么要在这里中间?简单的方法是 根据需要使用请求正文b, err = io.Copy(anyWriterOrMultiwriter, r.Body)b时请求的总内容长度。err == nil还b, err = io.Copy(ioutil.Discard, r.Body)

绝地无双

您可以编写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使用TeeReader,这是可扩展的。它将阅读器分成两部分,其中之一使用分配的内存计算大小。另外,在第一种情况下 maxmem := 4096  var buf bytes.Buffer  // comment this line out if you want to disable gathering metrics  resp.Body = io.TeeReader(resp.Body, &buf)   readsize := func(r io.Reader) int {    bytes := make([]byte, maxmem)    var size int      for {        read, err := r.Read(bytes)        if err == io.EOF {        break      }      size += read    }    return size  }  log.Printf("Size is %d", readsize(&buf))选项2不可扩展的方式(原始答案)您可以只读取正文,计算大小,然后解组为结构,这样它就变成了:    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    }
随时随地看视频慕课网APP

相关分类

Go
我要回答