限制要从HTTP响应读取的字节

时间:2018-10-08 08:26:00

标签: http go

我需要阅读用户提供的网址的回复

我不希望他们通过指向大型文件的链接使服务器超载。

我想最多读取N个字节,如果还有更多字节要读取,则返回错误。

我可以读取N个字节,但如何检测到该文件不完整(假设远程文件恰好是N个字节长的极端情况)?

3 个答案:

答案 0 :(得分:3)

只需尝试读取您的最大可接受大小加上1个字节。对于可接受的1MB大小:

var res *http.Response

b := make([]byte, 1<<20+1)
n, err := io.ReadFull(res.Body, b)
switch err {
case nil:
    log.Fatal("Response larger than 1MB")
case io.ErrUnexpectedEOF:
    // That's okay; the response is exactly 1MB or smaller.
    b = b[:n]
default:
    log.Fatal(err)
}

您也可以使用io.LimitedReader做同样的事情:

var res *http.Response

r := &io.LimitedReader{
    R: res.Body,
    N: 1<<20 + 1,
}

// handle response body somehow
io.Copy(ioutil.Discard, r)

if r.N == 0 {
    log.Fatal("Response larger than 1MB")
}

请注意,这两种方法均会限制未压缩的大小。如果响应被压缩,则更少的字节可能会遍历网络。您需要明确要限制网络或内存使用并相应地调整限制(可能视具体情况而定)。

答案 1 :(得分:3)

除了彼得的回答外,net/http软件包中还提供了一种现成的解决方案:http.MaxBytesReader()

func MaxBytesReader(w ResponseWriter, r io.ReadCloser, n int64) io.ReadCloser
  

MaxBytesReader与io.LimitReader相似,但旨在限制传入请求主体的大小。与io.LimitReader相比,MaxBytesReader的结果是ReadCloser,对于超出限制的Read返回非EOF错误,并在调用其Close方法时关闭基础阅读器。

最初,它是“设计”用于限制传入的 request 主体的大小,但它也可以用于限制传入的 response 主体。为此,只需为nil参数传递ResponseWriter

使用示例:

{
    body := ioutil.NopCloser(bytes.NewBuffer([]byte{0, 1, 2, 3, 4}))
    r := http.MaxBytesReader(nil, body, 4)
    buf, err := ioutil.ReadAll(r)
    fmt.Println("When body is large:", buf, err)
}

{
    body := ioutil.NopCloser(bytes.NewBuffer([]byte{0, 1, 2, 3, 4}))
    r := http.MaxBytesReader(nil, body, 5)
    buf, err := ioutil.ReadAll(r)
    fmt.Println("When body is exact (OK):", buf, err)
}

{
    body := ioutil.NopCloser(bytes.NewBuffer([]byte{0, 1, 2, 3, 4}))
    r := http.MaxBytesReader(nil, body, 6)
    buf, err := ioutil.ReadAll(r)
    fmt.Println("When body is small (OK):", buf, err)
}

输出(在Go Playground上尝试):

When body is large: [0 1 2 3] http: request body too large
When body is exact (OK): [0 1 2 3 4] <nil>
When body is small (OK): [0 1 2 3 4] <nil>

答案 2 :(得分:0)

您可以检查请求标头中的内容长度字段以获取总文件大小。