← Назад к вопросам
Что означают различные коды статусов HTTP, такие как 100, 200, 300, 400 и другие?
1.0 Junior🔥 151 комментариев
#Git и VCS#Soft Skills
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Полное руководство по HTTP статус кодам
HTTP статус коды сообщают о результате запроса. Они разделены на 5 категорий по первой цифре.
1xx: Informational (100-199)
Времённые ответы, информирующие о промежуточном состоянии запроса.
100 Continue — сервер готов получать тело запроса
101 Switching Protocols — сервер переходит на другой протокол (WebSocket)
102 Processing — сервер обрабатывает запрос (WebDAV)
Практический пример:
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
app = FastAPI()
@app.post("/upload")
async def upload_large_file(request: Request):
# Клиент отправит файл большого размера
# 100 Continue уже обработан FastAPI автоматически
body = await request.body()
return {"size": len(body)}
Использование в WebSocket:
from fastapi import WebSocket
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
# 101 Switching Protocols происходит автоматически
await websocket.accept() # Это инициирует переключение на WebSocket
while True:
data = await websocket.receive_text()
await websocket.send_text(f"Echo: {data}")
2xx: Success (200-299)
Запрос успешно выполнен. Это то, что хочет видеть клиент.
200 OK — стандартный успешный ответ
201 Created — ресурс был создан
202 Accepted — запрос принят, но обрабатывается асинхронно
204 No Content — успех, но нет тела ответа
206 Partial Content — только часть контента (для Range requests)
Примеры:
from fastapi import status
from fastapi.responses import Response
@app.get("/items")
async def get_items():
# 200 OK (по умолчанию для GET)
return [{"id": 1, "name": "Item 1"}]
@app.post("/items", status_code=status.HTTP_201_CREATED)
async def create_item(item: Item):
# 201 Created — ресурс был создан
return {"id": 1, "name": item.name}
@app.post("/background-job", status_code=status.HTTP_202_ACCEPTED)
async def start_background_job(job_data: dict):
# 202 Accepted — запрос в очереди, обработается позже
# asyncio.create_task(process_job(job_data))
return {"job_id": "abc-123", "status": "queued"}
@app.delete("/items/{item_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_item(item_id: int):
# 204 No Content — успех, но нечего возвращать
# db.delete(item)
return None # Важно: нет тела ответа!
@app.get("/large-file")
async def get_large_file(range: str = Header(None)):
# 206 Partial Content — для больших файлов
if range:
# Парсим Range header и возвращаем только нужную часть
return Response(
content=file_content,
status_code=206,
headers={"Content-Range": "bytes 0-1023/10000"}
)
return {"error": "Use Range header"}
3xx: Redirection (300-399)
Ресурс находится в другом месте. Клиент должен сделать дополнительный запрос.
300 Multiple Choices — несколько вариантов (редко)
301 Moved Permanently — ресурс перемещен постоянно
302 Found — ресурс временно в другом месте
304 Not Modified — кэшированная версия актуальна
307 Temporary Redirect — временный редирект (сохраняет метод)
308 Permanent Redirect — постоянный редирект (сохраняет метод)
Примеры:
from fastapi.responses import RedirectResponse
from fastapi import status
@app.get("/old-endpoint")
async def old_endpoint():
# 301 Moved Permanently — SEO-friendly redirect
return RedirectResponse(
url="/new-endpoint",
status_code=status.HTTP_301_MOVED_PERMANENTLY
)
@app.get("/temporary")
async def temporary_redirect():
# 302 Found — временный редирект
return RedirectResponse(
url="/new-location",
status_code=status.HTTP_302_FOUND
)
@app.get("/files/{file_path}")
async def serve_file(file_path: str, request: Request):
# 304 Not Modified — если клиент имеет актуальный кэш
etag = request.headers.get("If-None-Match")
current_etag = f'\"version-123\"' # Версия файла
if etag == current_etag:
return Response(status_code=status.HTTP_304_NOT_MODIFIED)
# Иначе возвращаем файл с 200
return FileResponse(
file_path,
headers={"ETag": current_etag}
)
@app.post("/form-redirect")
async def form_redirect():
# 307 Temporary Redirect — сохраняет POST метод при редиректе
return RedirectResponse(
url="/success",
status_code=status.HTTP_307_TEMPORARY_REDIRECT
)
4xx: Client Error (400-499)
Ошибка клиента. Запрос содержит ошибку, повтор не поможет.
400 Bad Request — неправильный формат
401 Unauthorized — требуется аутентификация
403 Forbidden — нет прав доступа
404 Not Found — ресурс не существует
405 Method Not Allowed — неправильный HTTP метод
409 Conflict — конфликт (дублирование)
410 Gone — ресурс удален
413 Payload Too Large — слишком большой файл
415 Unsupported Media Type — неправильный Content-Type
422 Unprocessable Entity — валидация не прошла
429 Too Many Requests — rate limiting
Примеры см. в предыдущем ответе о 4xx кодах
5xx: Server Error (500-599)
Ошибка сервера. Обычно можно повторить запрос позже.
500 Internal Server Error — неожиданная ошибка на сервере
501 Not Implemented — функция не реализована
502 Bad Gateway — шлюз получил неправильный ответ от upstream
503 Service Unavailable — сервер временно недоступен
504 Gateway Timeout — timeout ответа от upstream
Примеры:
from fastapi import FastAPI
from fastapi.exceptions import HTTPException
from fastapi.responses import JSONResponse
app = FastAPI()
@app.get("/items/{item_id}")
async def get_item(item_id: int):
try:
result = expensive_operation(item_id)
return result
except DatabaseError:
# 500 Internal Server Error
raise HTTPException(
status_code=500,
detail="Database error, please try again later"
)
@app.get("/not-implemented")
async def not_implemented():
# 501 Not Implemented
raise HTTPException(
status_code=501,
detail="This feature is not implemented yet"
)
@app.get("/upstream-call")
async def call_upstream():
try:
response = await httpx.get("https://external-service.com/api", timeout=5)
return response.json()
except httpx.TimeoutException:
# 504 Gateway Timeout
raise HTTPException(
status_code=504,
detail="Upstream service timeout"
)
except Exception:
# 502 Bad Gateway
raise HTTPException(
status_code=502,
detail="Upstream service error"
)
# Обработчик для 503 Service Unavailable
@app.get("/status")
async def service_status(db: Session = Depends(get_db)):
try:
db.execute(text("SELECT 1"))
return {"status": "operational"}
except:
# 503 Service Unavailable
raise HTTPException(
status_code=503,
detail="Service temporarily unavailable"
)
# Глобальный обработчик ошибок
@app.exception_handler(Exception)
async def global_exception_handler(request, exc):
logger.error(f"Unhandled exception: {exc}")
return JSONResponse(
status_code=500,
content={"error": "Internal server error"}
)
Таблица всех кодов
| Категория | Коды | Значение | Действие клиента |
|---|---|---|---|
| 1xx | 100-199 | Информация | Ждёт или продолжает |
| 2xx | 200-299 | Успех | Использует ответ |
| 3xx | 300-399 | Редирект | Переходит по ссылке |
| 4xx | 400-499 | Ошибка клиента | Исправляет запрос |
| 5xx | 500-599 | Ошибка сервера | Повторяет позже |
Выбор правильного кода
Алгоритм выбора:
Запрос выполнен успешно?
├─ Да
│ ├─ Есть ли результат?
│ │ ├─ Да → 200 OK
│ │ └─ Нет → 204 No Content
│ ├─ Был ли создан ресурс? → 201 Created
│ └─ Запрос в очереди? → 202 Accepted
│
├─ Нет, клиент должен сделать другой запрос?
│ ├─ Ресурс в другом месте?
│ │ ├─ Постоянно → 301/308
│ │ └─ Временно → 302/307
│ └─ Актуальный кэш? → 304
│
├─ Нет, ошибка клиента?
│ ├─ Неправильный формат → 400
│ ├─ Нет аутентификации → 401
│ ├─ Нет прав → 403
│ ├─ Не существует → 404
│ ├─ Конфликт → 409
│ ├─ Валидация → 422
│ ├─ Rate limit → 429
│ └─ Другое → 400
│
└─ Нет, ошибка сервера?
├─ Неожиданная ошибка → 500
├─ Не реализовано → 501
├─ Upstream ошибка → 502
├─ Сервер недоступен → 503
└─ Timeout → 504
Best Practices
- Выбирай точный код — не все ошибки это 400
- Возвращай тело ответа — объясни что случилось (кроме 204, 304)
- Логируй 5xx ошибки — это реальные проблемы
- Не логируй 4xx — это обычно вина клиента
- Используй стандарты — не выдумывай свои коды
- Помогай клиенту — чёткие сообщения об ошибках
- Возвращай скорость — правильный код помогает клиентам оптимизироваться
Примеры из реальных проектов
# Правильное обращение к ошибкам
class APIResponse:
def success(data=None, status=200):
return {"success": True, "data": data, "status": status}
def error(message: str, code: int = 400, details=None):
return {
"success": False,
"error": message,
"code": code,
"details": details
}
# Использование
@app.post("/users")
async def create_user(user: UserCreate):
if not is_email_valid(user.email):
return APIResponse.error(
message="Invalid email format",
code=400
), 400
if email_exists(user.email):
return APIResponse.error(
message="Email already registered",
code=409
), 409
new_user = db.create_user(user)
return APIResponse.success(
data=new_user.dict(),
status=201
), 201