@t38c3j

Как принудительно закрыть соединение без ожидания полного ответа запроса?

Есть программа на python для скачивания только части файла из ответа запроса, aiohttp автоматически закрывает соединение после выхода из контекста без ожидания получения полного ответа от сервера, то есть, если файл весит 1GB a мы прочитали например только 50MB по необходимости, то оставшееся мы не будем гонять по сети (проверено мониторингом сети)
Код на python

async with c.get(...) as resp:
    if resp.status != 200:
        raise Exception(...)
    if int.from_bytes(await resp.content.read(4), 'little') != 288633362:
        raise Exception(...)
    if int.from_bytes(await resp.content.read(4), 'little') != 2:
        raise Exception(...)
    async with aiofiles.open(...) as f:
        block_length = int.from_bytes(await resp.content.read(4), 'little')
        await f.write(await resp.content.read(block_length))
        await f.write(b'\n')
        block_length = int.from_bytes(await resp.content.read(4), 'little')
        await f.write(await resp.content.read(block_length))


Пытаюсь повторить данное поведение в go с использованием net/http, но ответ все равно читается полностью и только потом закрывается соединение.
Код на go

func verifySignature(r io.Reader) error {
	var s uint32
	if err := binary.Read(r, binary.LittleEndian, &s); err != nil {
		return ...
	}
	if s != 288633362 {
		return ...
	}
	return nil
}

func validateBlockCount(r io.Reader) error {
	var c uint32
	if err := binary.Read(r, binary.LittleEndian, &c); err != nil {
		return ...
	}
	if c != 2 {
		return ...
	}
	return nil
}

func parseBlock(r io.Reader) ([]byte, error) {
	var l uint32
	if err := binary.Read(r, binary.LittleEndian, &l); err != nil {
		return nil, ...
	}
	d := make([]byte, l)
	if err := binary.Read(r, binary.LittleEndian, &d); err != nil {
		return nil, ...
	}
	return d, nil
}

func download(...) {
	req, err := http.NewRequest(...)
	if err != nil {
		return ...
	}
	resp, err := c.Do(req)
	if err != nil {
		return ...

	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return ...
	}
	r := bufio.NewReader(resp.Body)
	if err := verifySignature(r); err != nil {
		return ...
	}
	if err := validateBlockCount(r); err != nil {
		return ...
	}
	..., err = parseBlock(r)
	if err != nil {
		return ...
	}
	..., err = parseBlock(r)
	if err != nil {
		return ...
    }
     ...
}


Как принудительно закрыть соединение без ожидания полного ответа запроса?
  • Вопрос задан
  • 153 просмотра
Решения вопроса 1
@iburanguloff
Fullstack web developer
Для этого отлично подойдут контексты (пакет context) в связке с функцией http.NewRequestWithContext, который принимает контекст одним из параметров. В момент, когда вы поймете, что запрос следует прервать - можно отменить контекст и соединение прервется. Например функция context.WithCancel создает контекст и возвращает кроме него еще функцию, вызвав которую контекст можно закрыть
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы