golang在server端如何流式读取http request的body(body很大)

rt

共 7 个回复


jimmykuu

defer r.Body.Close()
buf := make([]byte, 1024)          # 1024为缓存大小,即每次读出的最大数据
for {
    n, err := r.Body.Read(buf)     # 为这次读出的数据大小
    if err != nil {
        break
    }
}
# 0

xueliufeng

谢谢,这个处理逻辑可以在handlerfunc里写么?新手^^

# 1

jimmykuu

就是在handler里写的

# 2

spongerabit

@jimmykuu
有个问题,用给你给的demo,读出来的n好像都不是确定的,我需要每次读出来的是固定大小的,请问这个该怎么处理?

# 3

stevewang

br := bufio.NewReader(r.Body)
buf := make([]byte, 128)
for {
    _, err := io.ReadFull(br, buf)
    if err != nil {
        break
    }
    // ...
}
# 4

superGo

@jimmykuu
第一次,是下面的代码写的,收到的数据,有时会出错,但是大小肯定是小于定义的4096的

 var bodyData []byte = make([]byte, 4096)
    bodyLen, readErr := req.Body.Read(bodyData)
    if readErr != nil && readErr != io.EOF {
        fmt.Println("read body error")
        return "", readErr
    } else {
        fmt.Printf("the body len[%d],body: %s\n", bodyLen, string(bodyData))
    }
    var realData []byte = make([]byte, bodyLen)
    copy(realData, bodyData)

第二次是下面的写法,也就是您推荐的。也会出错,虽然读的大小与抓包的大小一致。但是数据不一致。有的字段读了两次,同时另一些字段没有读到

for {
    n, err := req.Body.Read(buf) // 为这次读出的数据大小
    fmt.Printf("before n=%d,err=%v",n,err)
    if err != nil && err != io.EOF {
        return "",err
    }
    if err == io.EOF { /* && n != 0*/
        buffer.Write(buf)
        count +=n
        break
    }
    count += n
    buffer.Write(buf)
}
# 5

jimmykuu

第一种写法虽然收到的数据一定小于 4096,但是不能保证一次就能 Read 进来,所有不行。

第二种写法,写入 buffer 的时候会把整个 buf slice 里的内容都写进去,用 make 创建的 slice 会自动补 0,正确的写法应该这样。

for {
    n, err := req.Body.Read(buf)
    fmt.Printf("before n=%d,err=%v",n,err)
    if err != nil && err != io.EOF {
        return "",err
    }
    if err == io.EOF {
        break
    }
    count += n
    buffer.Write(buf[:n])
}
# 6