Статус-коды — трёхзначные числа в ответе HTTP, определяющие результат запроса. На экзамене Symfony необходимо знать точное значение каждого кода, особенно разницу между похожими кодами.
Классы статус-кодов
| Диапазон | Класс | Описание |
|---|---|---|
1xx |
Informational | Запрос принят, продолжается обработка |
2xx |
Success | Запрос успешно обработан |
3xx |
Redirection | Для завершения нужно дополнительное действие |
4xx |
Client Error | Ошибка на стороне клиента |
5xx |
Server Error | Ошибка на стороне сервера |
1xx — Информационные
| Код | Имя | Описание |
|---|---|---|
100 |
Continue | Сервер получил заголовки, клиент может отправить тело |
101 |
Switching Protocols | Переключение протокола (WebSocket) |
103 |
Early Hints | Preload ресурсов до финального ответа |
<?php
declare(strict_types=1);
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\WebLink\Link;
// 103 Early Hints — preload resources before main response
class ProductController extends AbstractController
{
public function show(int $id): Response
{
// Send 103 Early Hints for preloading CSS/JS
$this->sendEarlyHints([
new Link('preload', '/build/app.css', ['as' => 'style']),
new Link('preload', '/build/app.js', ['as' => 'script']),
]);
// Process the heavy request...
$product = $this->repository->find($id);
return $this->render('product/show.html.twig', [
'product' => $product,
]);
}
}
2xx — Успешные
| Код | Имя | Когда использовать | Symfony-константа |
|---|---|---|---|
200 |
OK | Успешный GET, PUT, PATCH | Response::HTTP_OK |
201 |
Created | Успешный POST (ресурс создан) | Response::HTTP_CREATED |
202 |
Accepted | Запрос принят, но ещё не обработан | Response::HTTP_ACCEPTED |
204 |
No Content | Успешный DELETE (нет тела ответа) | Response::HTTP_NO_CONTENT |
206 |
Partial Content | Частичная загрузка (Range) | Response::HTTP_PARTIAL_CONTENT |
<?php
declare(strict_types=1);
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
// 200 — standard success
return new JsonResponse(['data' => $items]);
// 201 — resource created (include Location header!)
return new JsonResponse(
['id' => $product->getId()],
Response::HTTP_CREATED,
['Location' => '/api/products/' . $product->getId()]
);
// 202 — accepted for async processing
return new JsonResponse(
['status' => 'processing', 'job_id' => $jobId],
Response::HTTP_ACCEPTED
);
// 204 — successful delete, no body
return new Response(null, Response::HTTP_NO_CONTENT);
Подвох экзамена:
201 Createdдолжен содержать заголовокLocationс URL нового ресурса.204 No ContentНЕ должен содержать тело ответа. Если на экзамене видите201безLocationили204с телом — это неправильно.
3xx — Перенаправления
| Код | Имя | Сохраняет метод | Постоянный | Использование |
|---|---|---|---|---|
301 |
Moved Permanently | Нет (→ GET) | Да | SEO-редирект |
302 |
Found | Нет (→ GET) | Нет | Временный редирект |
303 |
See Other | Нет (→ GET) | Нет | После POST (PRG) |
307 |
Temporary Redirect | Да | Нет | Временный, метод сохраняется |
308 |
Permanent Redirect | Да | Да | Постоянный, метод сохраняется |
304 |
Not Modified | — | — | Кэш валиден |
Подвох экзамена: Главная разница между
301и308— сохранение HTTP-метода. При301POST может стать GET (браузеры так делают). При308метод ВСЕГДА сохраняется. Аналогично302vs307. Это критически важный вопрос на экзамене.
<?php
declare(strict_types=1);
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
// 301 — permanent redirect (browser caches!)
return new RedirectResponse('/new-url', Response::HTTP_MOVED_PERMANENTLY);
// 302 — temporary redirect (default in Symfony)
return $this->redirect('/temporary-url'); // 302 by default
// 303 — redirect after POST (PRG pattern)
return $this->redirectToRoute('product_list', [], Response::HTTP_SEE_OTHER);
// 307 — temporary redirect preserving method
return new RedirectResponse('/api/v2/products', Response::HTTP_TEMPORARY_REDIRECT);
// 308 — permanent redirect preserving method
return new RedirectResponse('/api/v2/products', Response::HTTP_PERMANENTLY_REDIRECT);
304 Not Modified
<?php
declare(strict_types=1);
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class ArticleController extends AbstractController
{
public function show(int $id, Request $request): Response
{
$article = $this->repository->find($id);
$lastModified = $article->getUpdatedAt();
$response = new Response();
$response->setLastModified($lastModified);
$response->setEtag(md5($article->getContent()));
// If client cache is still valid → 304
if ($response->isNotModified($request)) {
return $response; // 304, no body
}
$response->setContent($this->renderView('article/show.html.twig', [
'article' => $article,
]));
return $response;
}
}
4xx — Ошибки клиента
| Код | Имя | Когда | Symfony-константа |
|---|---|---|---|
400 |
Bad Request | Невалидный синтаксис запроса | HTTP_BAD_REQUEST |
401 |
Unauthorized | Не аутентифицирован | HTTP_UNAUTHORIZED |
403 |
Forbidden | Аутентифицирован, но нет доступа | HTTP_FORBIDDEN |
404 |
Not Found | Ресурс не найден | HTTP_NOT_FOUND |
405 |
Method Not Allowed | Метод не поддерживается | HTTP_METHOD_NOT_ALLOWED |
409 |
Conflict | Конфликт (параллельное изменение) | HTTP_CONFLICT |
415 |
Unsupported Media Type | Неподдерживаемый Content-Type | HTTP_UNSUPPORTED_MEDIA_TYPE |
422 |
Unprocessable Entity | Валидация не прошла | HTTP_UNPROCESSABLE_ENTITY |
429 |
Too Many Requests | Rate limiting | HTTP_TOO_MANY_REQUESTS |
Подвох экзамена:
401 Unauthorizedна самом деле означает "Unauthenticated" — пользователь НЕ представился.403 Forbidden— пользователь представился (authenticated), но у него НЕТ прав (not authorized). Название401вводит в заблуждение. Запомните: 401 = "кто ты?", 403 = "я знаю кто ты, но тебе нельзя".
400 vs 422
<?php
declare(strict_types=1);
// 400 Bad Request — request cannot be parsed
// (malformed JSON, missing required headers, invalid syntax)
if ($request->getContentTypeFormat() !== 'json') {
throw new BadRequestHttpException('Content-Type must be application/json');
}
// 422 Unprocessable Entity — request is syntactically correct
// but semantically invalid (validation errors)
$violations = $validator->validate($dto);
if (count($violations) > 0) {
throw new UnprocessableEntityHttpException('Validation failed');
}
405 Method Not Allowed
<?php
declare(strict_types=1);
// Symfony automatically returns 405 when route exists
// but requested method is not allowed
// Response MUST include Allow header
// GET /api/products → 200 (route exists for GET)
// DELETE /api/products → 405 (route exists, but only GET/POST allowed)
// Response: 405 Method Not Allowed
// Allow: GET, POST
Подвох экзамена: При
405ответ ОБЯЗАН содержать заголовокAllowс перечислением допустимых методов. Symfony добавляет его автоматически. При429рекомендуется включать заголовокRetry-After.
5xx — Ошибки сервера
| Код | Имя | Когда | Symfony-константа |
|---|---|---|---|
500 |
Internal Server Error | Необработанное исключение | HTTP_INTERNAL_SERVER_ERROR |
502 |
Bad Gateway | Прокси получил ошибку от upstream | HTTP_BAD_GATEWAY |
503 |
Service Unavailable | Сервер временно недоступен | HTTP_SERVICE_UNAVAILABLE |
504 |
Gateway Timeout | Прокси не дождался ответа upstream | HTTP_GATEWAY_TIMEOUT |
<?php
declare(strict_types=1);
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
// 503 with Retry-After header
throw new ServiceUnavailableHttpException(
300, // Retry-After: 300 seconds
'Database maintenance in progress'
);
Константы Symfony Response
<?php
declare(strict_types=1);
use Symfony\Component\HttpFoundation\Response;
// All status codes as class constants
Response::HTTP_OK; // 200
Response::HTTP_CREATED; // 201
Response::HTTP_NO_CONTENT; // 204
Response::HTTP_MOVED_PERMANENTLY; // 301
Response::HTTP_FOUND; // 302
Response::HTTP_SEE_OTHER; // 303
Response::HTTP_NOT_MODIFIED; // 304
Response::HTTP_TEMPORARY_REDIRECT; // 307
Response::HTTP_PERMANENTLY_REDIRECT; // 308
Response::HTTP_BAD_REQUEST; // 400
Response::HTTP_UNAUTHORIZED; // 401
Response::HTTP_FORBIDDEN; // 403
Response::HTTP_NOT_FOUND; // 404
Response::HTTP_METHOD_NOT_ALLOWED; // 405
Response::HTTP_CONFLICT; // 409
Response::HTTP_UNPROCESSABLE_ENTITY; // 422
Response::HTTP_TOO_MANY_REQUESTS; // 429
Response::HTTP_INTERNAL_SERVER_ERROR; // 500
Response::HTTP_BAD_GATEWAY; // 502
Response::HTTP_SERVICE_UNAVAILABLE; // 503
// Check if status code is successful
$response->isSuccessful(); // 2xx
$response->isRedirection(); // 3xx
$response->isClientError(); // 4xx
$response->isServerError(); // 5xx
Подвох экзамена: Symfony предоставляет метод
Response::isInformational()для 1xx,isSuccessful()для 2xx и т.д. МетодisOk()проверяет ТОЛЬКО код 200, а не весь диапазон 2xx. Не путайтеisOk()иisSuccessful().