Ответ
Размер тела HTTP-сообщения (как запроса, так и ответа) определяется одним из трех основных способов:
-
Заголовок
Content-Length
Это самый распространенный способ. Заголовок указывает точный размер тела сообщения в байтах. Сервер или клиент читает ровно столько байт, сколько указано в этом заголовке.
POST /api/users HTTP/1.1 Host: example.com Content-Type: application/json Content-Length: 38 {"username": "test", "score": 100}
-
Заголовок
Transfer-Encoding: chunked
Этот механизм используется, когда размер контента неизвестен заранее (например, при стриминге данных). Тело сообщения передается по частям (чанками). Каждый чанк предваряется его размером в шестнадцатеричном формате, а конец передачи обозначается чанком нулевой длины.
HTTP/1.1 200 OK Content-Type: text/plain Transfer-Encoding: chunked 4rn // 4 байта данных Wikirn 5rn // 5 байт данных pediarn Ern // 14 байт данных in rnrnchunks.rn 0rn // чанк нулевой длины - конец rn
-
Закрытие соединения сервером
Если отсутствуют оба заголовка (
Content-Length
иTransfer-Encoding
), клиент считает, что тело сообщения закончилось, когда сервер закрывает TCP-соединение. Этот метод считается устаревшим для HTTP/1.1, так как он не позволяет использовать постоянные соединения (Keep-Alive
).
В Go эта логика инкапсулирована в стандартной библиотеке. При чтении http.Request.Body
или http.Response.Body
(которые являются io.ReadCloser
), вам не нужно вручную парсить эти заголовки. Go сам определяет, как читать тело сообщения, основываясь на них.
// Пример чтения тела запроса на сервере
func handler(w http.ResponseWriter, r *http.Request) {
// Go автоматически обработает Content-Length или chunked encoding
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Can't read body", http.StatusBadRequest)
return
}
// ... используем body
}