Как в протоколе HTTP определяется размер тела запроса или ответа?

Ответ

Размер тела HTTP-сообщения (как запроса, так и ответа) определяется одним из трех основных способов:

  1. Заголовок Content-Length

    Это самый распространенный способ. Заголовок указывает точный размер тела сообщения в байтах. Сервер или клиент читает ровно столько байт, сколько указано в этом заголовке.

    POST /api/users HTTP/1.1
    Host: example.com
    Content-Type: application/json
    Content-Length: 38
    
    {"username": "test", "score": 100}
  2. Заголовок 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
  3. Закрытие соединения сервером

    Если отсутствуют оба заголовка (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
}