Ограничить количество байтов для чтения из ответа HTTP - PullRequest
0 голосов
/ 08 октября 2018

Мне нужно прочитать ответы от предоставленных пользователем URL-адресов

Я не хочу, чтобы они перегружали мой сервер ссылками на огромные файлы.

Я хочу прочитать N байтов максимум и вернутьошибка, если есть еще байты для чтения.

Я могу прочитать N байтов, но, как я обнаружил, этот файл неполон (если предположить, что удаленный файл имеет длину ровно N байтов)?

Ответы [ 3 ]

0 голосов
/ 08 октября 2018

Просто попробуйте прочитать ваш максимально допустимый размер плюс 1 байт.Для приемлемого размера 1 МБ:

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")
}

Обратите внимание, что оба метода ограничивают несжатый размер.Значительно меньшее количество байтов может пройти через сеть, если ответ сжат.Вам необходимо четко определить, хотите ли вы ограничить использование сети или памяти и отрегулировать ограничение соответствующим образом, возможно, в индивидуальном порядке.

0 голосов
/ 08 октября 2018

Кроме ответа Питера, в пакете net/http есть готовое решение: http.MaxBytesReader():

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

MaxBytesReader isпохож на io.LimitReader, но предназначен для ограничения размера тела входящих запросов.В отличие от io.LimitReader, результатом MaxBytesReader является ReadCloser, он возвращает ошибку, не связанную с EOF, для чтения вне предела и закрывает базовый считыватель при вызове его метода Close.

Первоначально это было«предназначен» для ограничения размера входящих запросов тел, но также может использоваться для ограничения входящих ответов тел.Для этого просто передайте 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>
0 голосов
/ 08 октября 2018

Вы можете проверить поле длины содержимого в заголовке запроса, чтобы получить общий размер файла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...