我需要阅读用户提供的网址的回复
我不希望他们通过指向大型文件的链接使服务器超载。
我想最多读取N个字节,如果还有更多字节要读取,则返回错误。
我可以读取N个字节,但如何检测到该文件不完整(假设远程文件恰好是N个字节长的极端情况)?
答案 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)
您可以检查请求标头中的内容长度字段以获取总文件大小。