← Назад к вопросам

Из чего состоит http ответ

1.2 Junior🔥 191 комментариев
#REST API и HTTP

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Структура HTTP ответа

HTTP ответ — это сообщение, которое сервер отправляет клиенту в ответ на HTTP запрос. Он состоит из трёх основных частей: статусная строка, заголовки и тело.

Структура HTTP ответа

[Статусная строка]
HTTP/1.1 200 OK

[Заголовки]
Content-Type: application/json
Content-Length: 348
Set-Cookie: session_id=abc123; Path=/
Cache-Control: max-age=3600

[Пустая строка]

[Тело (Body)]
{"name": "Alice", "age": 30, "email": "alice@example.com"}

1. Статусная строка (Status Line)

Описывает версию HTTP, статус-код и статус-сообщение:

HTTP/1.1 200 OK
│        │   │
│        │   └─ Статус-сообщение (Reason Phrase)
│        └────── Статус-код (Status Code)
└─────────────── HTTP версия

Основные статус-коды:

# 2xx — Успех
200 OK                      # Запрос успешен, ответ содержит данные
201 Created                 # Ресурс создан
204 No Content              # Успех, но нет содержимого

# 3xx — Перенаправление
301 Moved Permanently       # Ресурс переместился навсегда
302 Found                   # Ресурс временно переместился
304 Not Modified            # Кэш актуален, не отправляем тело

# 4xx — Ошибка клиента
400 Bad Request             # Неверный формат запроса
401 Unauthorized            # Требуется аутентификация
403 Forbidden               # Доступ запрещён
404 Not Found               # Ресурс не найден
405 Method Not Allowed      # HTTP метод не поддерживается
429 Too Many Requests       # Rate limiting (слишком много запросов)

# 5xx — Ошибка сервера
500 Internal Server Error   # Внутренняя ошибка сервера
502 Bad Gateway             # Неверный ответ от upstream сервера
503 Service Unavailable     # Сервер временно недоступен

2. Заголовки (Headers)

Это пары ключ-значение, содержащие метаинформацию о ответе:

Content-Type: application/json
Content-Length: 348
Server: nginx/1.21.0
Date: Wed, 20 Mar 2024 10:30:00 GMT
Set-Cookie: session_id=abc123; Path=/; Secure; HttpOnly
Cache-Control: max-age=3600
Location: https://example.com/new-resource
Access-Control-Allow-Origin: *
Authorization: Bearer eyJhbGciOiJIUzI1NiJ...

Основные заголовки:

# Информация о содержимом
Content-Type: application/json           # Тип данных (MIME type)
Content-Length: 348                      # Размер тела в байтах
Content-Encoding: gzip                   # Сжатие (gzip, deflate, br)

# Информация о сервере
Server: Apache/2.4.41                    # Тип и версия сервера
Date: Wed, 20 Mar 2024 10:30:00 GMT     # Дата отправки ответа

# Кэширование
Cache-Control: max-age=3600              # Время кэширования
ETag: "33a64df..."                      # Уникальный идентификатор версии
Last-Modified: Wed, 19 Mar 2024 15:00:00 # Последнее изменение

# Перенаправления
Location: https://example.com/resource   # Новый URL при 3xx

# Cookies
Set-Cookie: sessionid=abc123;            # Установка cookie
             Path=/;                     # Путь
             Secure;                     # Только HTTPS
             HttpOnly;                   # Недоступна для JavaScript
             SameSite=Strict              # Защита от CSRF

# CORS (Cross-Origin Resource Sharing)
Access-Control-Allow-Origin: *           # Кто может запрашивать
Access-Control-Allow-Methods: GET, POST  # Разрешённые методы
Access-Control-Allow-Headers: Content-Type # Разрешённые заголовки

# Безопасность
Strict-Transport-Security: max-age=31536000  # HTTPS обязателен
X-Content-Type-Options: nosniff              # Защита от MIME sniffing
X-Frame-Options: DENY                        # Защита от clickjacking
Content-Security-Policy: default-src 'self'  # Контроль контента

# Аутентификация и авторизация
Authorization: Bearer eyJhbGciOiJIUzI1NiJ... # JWT токен
WWW-Authenticate: Bearer realm="api"         # Требуется авторизация

# Custom заголовки (начинаются с X-)
X-API-Version: 1.0
X-Custom-Header: custom-value

3. Пустая строка

Отделяет заголовки от тела:

[Последний заголовок]

[Пустая строка - два переноса строки: \r\n\r\n]

[Начало тела]

4. Тело ответа (Response Body)

Фактические данные, которые отправляет сервер:

# JSON
{"id": 1, "name": "Alice", "email": "alice@example.com"}

# HTML
<html>
  <head><title>Example</title></head>
  <body><h1>Hello, World!</h1></body>
</html>

# XML
<?xml version="1.0" encoding="UTF-8"?>
<user>
  <id>1</id>
  <name>Alice</name>
</user>

# Бинарные данные (изображение, PDF и т.д.)
[Бинарные данные]

# Пусто (при 204 No Content)

Полный пример HTTP ответа

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 55
Cache-Control: max-age=3600
Date: Wed, 20 Mar 2024 10:30:00 GMT
Server: FastAPI
Set-Cookie: session_id=abc123; Path=/

{"id": 1, "name": "Alice", "age": 30, "email": "..."}

Парсинг HTTP ответа в Python

import requests
from urllib.parse import urlparse
from http.client import HTTPConnection

# 1. Используя requests (проще)
response = requests.get("https://api.example.com/users/1")

# Статусная строка
print(response.status_code)  # 200
print(response.reason)       # OK

# Заголовки
print(response.headers)      # Словарь заголовков
print(response.headers["Content-Type"])  # application/json
print(response.cookies)      # Cookies

# Тело
print(response.text)         # Как строка
print(response.content)      # Как байты
print(response.json())       # Распарсено как JSON

Пример с низкоуровневым сокетом:

import socket

# Сырой HTTP запрос и ответ
socket_obj = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_obj.connect(("example.com", 80))

# Отправляем HTTP запрос
request = b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
socket_obj.send(request)

# Получаем HTTP ответ
response = socket_obj.recv(4096).decode()
print(response)
# Получим:
# HTTP/1.1 200 OK
# Content-Type: text/html
# Content-Length: 1234
# [пусто]
# <html>...</html>

socket_obj.close()

Различные типы ответов

1. JSON API ответ (200 OK)

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 27

{"status": "success", "data": {}}

2. Ошибка валидации (400 Bad Request)

HTTP/1.1 400 Bad Request
Content-Type: application/json
Content-Length: 45

{"error": "Email is required"}

3. Не найдено (404 Not Found)

HTTP/1.1 404 Not Found
Content-Type: text/html
Content-Length: 26

<h1>Not Found</h1>

4. Перенаправление (301 Moved Permanently)

HTTP/1.1 301 Moved Permanently
Location: https://example.com/new-path
Content-Length: 0

[пустое тело]

5. Кэш не изменился (304 Not Modified)

HTTP/1.1 304 Not Modified
ETag: "33a64df..."
Cache-Control: max-age=3600
Content-Length: 0

[пустое тело]

Практический пример: создание ответа в FastAPI

from fastapi import FastAPI, Response
from fastapi.responses import JSONResponse, FileResponse

app = FastAPI()

# 1. Простой JSON ответ (автоматически генерируется)
@app.get("/users/{user_id}")
async def get_user(user_id: int):
    return {"id": user_id, "name": "Alice"}
# Ответ:
# HTTP/1.1 200 OK
# Content-Type: application/json
# {"id": 1, "name": "Alice"}

# 2. Кастомный статус-код и заголовки
@app.post("/users")
async def create_user(name: str):
    user = {"id": 1, "name": name}
    return JSONResponse(
        content=user,
        status_code=201,  # Created
        headers={"X-User-ID": "1"}
    )
# Ответ:
# HTTP/1.1 201 Created
# Content-Type: application/json
# X-User-ID: 1
# {"id": 1, "name": "..."}

# 3. Ответ без тела
@app.delete("/users/{user_id}")
async def delete_user(user_id: int):
    return Response(status_code=204)  # No Content
# Ответ:
# HTTP/1.1 204 No Content
# [пустое тело]

# 4. Скачивание файла
@app.get("/download/report.pdf")
async def download_report():
    return FileResponse(
        path="/tmp/report.pdf",
        filename="report.pdf",
        media_type="application/pdf"
    )
# Ответ:
# HTTP/1.1 200 OK
# Content-Type: application/pdf
# Content-Disposition: attachment; filename="report.pdf"
# [бинарные данные PDF]

# 5. Кастомные заголовки и Cookies
@app.get("/login")
async def login():
    response = JSONResponse({"status": "logged_in"})
    response.set_cookie(
        key="session_id",
        value="abc123",
        max_age=3600,
        secure=True,
        httponly=True
    )
    response.headers["X-Custom"] = "value"
    return response

Размер и производительность

# Проверка размера ответа
response = requests.get("https://api.example.com/data")

headers_size = sum(len(f"{k}: {v}") for k, v in response.headers.items())
body_size = len(response.content)

print(f"Заголовки: {headers_size} байт")
print(f"Тело: {body_size} байт")
print(f"Total: {headers_size + body_size} байт")

# Сжатие
if "gzip" in response.headers.get("Content-Encoding", ""):
    print("Ответ сжат gzip")

Вывод

HTTP ответ состоит из:

  1. Статусная строка — версия HTTP, статус-код (200, 404, 500 и т.д.) и сообщение
  2. Заголовки — метаинформация (Content-Type, Content-Length, Cookies и т.д.)
  3. Пустая строка — разделитель
  4. Тело — фактические данные (JSON, HTML, бинарные данные или пусто)

Понимание структуры ответа критично для:

  • Отладки API запросов
  • Обработки ошибок
  • Работы с Cookies и сессиями
  • Оптимизации (кэширование, сжатие)
  • Безопасности (заголовки безопасности)