HTTP (HyperText Transfer Protocol) — основа веба. Symfony построен вокруг концепции Request/Response. На экзамене проверяют знание HTTP-методов, заголовков, структуры запросов и ответов.
Структура HTTP-запроса
HTTP-запрос состоит из трёх частей: стартовая строка, заголовки и тело.
POST /api/products HTTP/1.1 ← Request line
Host: example.com ← Headers
Content-Type: application/json
Authorization: Bearer abc123
Content-Length: 42
← Empty line (separator)
{"name":"Widget","price":9.99} ← Body
Компоненты стартовой строки
| Компонент | Описание | Пример |
|---|---|---|
| Метод | HTTP verb | GET, POST, PUT |
| URI | Путь ресурса | /api/products?page=1 |
| Версия | Версия протокола | HTTP/1.1, HTTP/2 |
Структура HTTP-ответа
HTTP/1.1 200 OK ← Status line
Content-Type: application/json ← Headers
Cache-Control: max-age=3600
X-Request-Id: abc-123
← Empty line
{"id":1,"name":"Widget"} ← Body
Symfony 8.0: Symfony 8.0 обновил HttpFoundation в соответствии с RFC 9110 (замена RFC 7230-7235). Основные изменения — в обработке заголовков и статус-кодов. RFC 9110 объединяет семантику HTTP в один документ.
HTTP-методы
Таблица методов
| Метод | Назначение | Тело запроса | Идемпотентный | Безопасный | Кэшируемый |
|---|---|---|---|---|---|
GET |
Получить ресурс | Нет | Да | Да | Да |
HEAD |
Только заголовки | Нет | Да | Да | Да |
POST |
Создать ресурс | Да | Нет | Нет | Условно |
PUT |
Заменить ресурс целиком | Да | Да | Нет | Нет |
PATCH |
Частичное обновление | Да | Нет | Нет | Нет |
DELETE |
Удалить ресурс | Может быть | Да | Нет | Нет |
OPTIONS |
Узнать возможности | Нет | Да | Да | Нет |
Подвох экзамена: Идемпотентность означает, что повторный запрос даёт тот же результат.
PUTидемпотентен (повторная замена = тот же результат), аPATCH— нет (повторный патч может дать другой результат).DELETEидемпотентен (удаление удалённого = ок). Это частый вопрос.
Подробнее о каждом методе
<?php
declare(strict_types=1);
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
#[Route('/api/products', name: 'api_product_')]
class ProductApiController extends AbstractController
{
// GET — retrieve resource(s), no side effects
#[Route('', name: 'list', methods: ['GET'])]
public function list(Request $request): JsonResponse
{
$page = $request->query->getInt('page', 1);
return $this->json(['page' => $page, 'items' => []]);
}
// POST — create a new resource
#[Route('', name: 'create', methods: ['POST'])]
public function create(Request $request): JsonResponse
{
$data = $request->toArray();
// Create product...
return $this->json(['id' => 1], Response::HTTP_CREATED);
}
// PUT — replace entire resource
#[Route('/{id}', name: 'replace', methods: ['PUT'])]
public function replace(int $id, Request $request): JsonResponse
{
$data = $request->toArray();
// Replace all fields of product $id
return $this->json(['id' => $id]);
}
// PATCH — partial update
#[Route('/{id}', name: 'update', methods: ['PATCH'])]
public function update(int $id, Request $request): JsonResponse
{
$data = $request->toArray();
// Update only provided fields
return $this->json(['id' => $id]);
}
// DELETE — remove resource
#[Route('/{id}', name: 'delete', methods: ['DELETE'])]
public function delete(int $id): Response
{
// Delete product $id
return new Response(null, Response::HTTP_NO_CONTENT);
}
// OPTIONS — describe communication options
#[Route('', name: 'options', methods: ['OPTIONS'])]
public function options(): Response
{
return new Response(null, 200, [
'Allow' => 'GET, POST, OPTIONS',
]);
}
}
Safe vs Idempotent vs Neither
Safe (безопасный): GET, HEAD, OPTIONS
Idempotent (идемпотент): GET, HEAD, OPTIONS, PUT, DELETE
Neither (ни то, ни другое): POST, PATCH
Подвох экзамена: Безопасный метод — тот, что не меняет состояние сервера. Идемпотентный — повторный вызов даёт тот же результат. Все безопасные методы идемпотентны, но не все идемпотентные — безопасны (PUT изменяет сервер, но идемпотентен).
Заголовки HTTP
Request Headers
| Заголовок | Назначение | Пример |
|---|---|---|
Host |
Доменное имя сервера | Host: api.example.com |
Accept |
Желаемый формат ответа | Accept: application/json |
Content-Type |
Формат тела запроса | Content-Type: application/json |
Authorization |
Авторизация | Authorization: Bearer token123 |
Accept-Language |
Желаемый язык | Accept-Language: ru-RU,en;q=0.9 |
User-Agent |
Клиентское ПО | User-Agent: Mozilla/5.0... |
Referer |
Откуда пришёл запрос | Referer: https://example.com/ |
Cookie |
Куки | Cookie: session=abc123 |
If-None-Match |
Условный запрос (ETag) | If-None-Match: "v1" |
If-Modified-Since |
Условный запрос (дата) | If-Modified-Since: Mon, 01 Jan... |
Response Headers
| Заголовок | Назначение | Пример |
|---|---|---|
Content-Type |
Формат тела ответа | Content-Type: text/html; charset=UTF-8 |
Content-Length |
Размер тела | Content-Length: 348 |
Cache-Control |
Инструкции кэширования | Cache-Control: max-age=3600 |
Set-Cookie |
Установить cookie | Set-Cookie: session=abc; HttpOnly |
Location |
Редирект | Location: /new-url |
ETag |
Версия ресурса | ETag: "33a64df5" |
Last-Modified |
Дата изменения | Last-Modified: Wed, 21 Oct... |
Allow |
Разрешённые методы | Allow: GET, POST, HEAD |
WWW-Authenticate |
Схема авторизации | WWW-Authenticate: Bearer |
HttpFoundation в Symfony
Symfony оборачивает HTTP в объекты Request и Response.
<?php
declare(strict_types=1);
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
// Creating Request from PHP globals
$request = Request::createFromGlobals();
// Accessing request data
$method = $request->getMethod(); // 'GET', 'POST', etc.
$uri = $request->getRequestUri(); // '/api/products?page=1'
$path = $request->getPathInfo(); // '/api/products'
$host = $request->getHost(); // 'example.com'
$scheme = $request->getScheme(); // 'https'
$isSecure = $request->isSecure(); // true
$isXhr = $request->isXmlHttpRequest(); // Ajax check
$clientIp = $request->getClientIp(); // '192.168.1.1'
$contentType = $request->getContentTypeFormat(); // 'json'
// Query parameters (?key=value)
$page = $request->query->get('page', '1');
// POST data
$name = $request->request->get('name');
// Headers
$auth = $request->headers->get('Authorization');
$accept = $request->headers->get('Accept');
// Creating Response
$response = new Response(
'Hello World',
Response::HTTP_OK,
['Content-Type' => 'text/plain']
);
$response->send();
Request Property Bags
| Свойство | Источник данных | PHP-эквивалент |
|---|---|---|
$request->query |
URL query string | $_GET |
$request->request |
POST body | $_POST |
$request->cookies |
Cookies | $_COOKIE |
$request->files |
Uploaded files | $_FILES |
$request->server |
Server vars | $_SERVER |
$request->headers |
HTTP headers | Из $_SERVER |
$request->attributes |
Route params & custom | Нет аналога |
Подвох экзамена:
$request->attributes— это НЕ HTTP-данные. Это внутренний bag Symfony для передачи данных между компонентами (route parameters, resolved objects и т.д.). На экзамене могут спросить откуда берутся route parameters — ответ: из$request->attributes.
HTTP/2 и HTTP/3
Отличия версий
| Характеристика | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| Транспорт | TCP | TCP | QUIC/UDP |
| Мультиплексирование | Нет | Да | Да |
| Сжатие заголовков | Нет | HPACK | QPACK |
| Server Push | Нет | Да | Нет |
| Текстовый/бинарный | Текст | Бинарный | Бинарный |
Symfony работает с любой версией HTTP через веб-сервер (Nginx, Caddy). Приложению не нужно заботиться о версии протокола — HttpFoundation абстрагирует различия.
Symfony 8.0: Symfony 8.0 улучшил поддержку HTTP/2 Server Push через
Linkheader и Preload. Однако Server Push deprecated в Chrome и не поддерживается в HTTP/3. Рекомендуется использовать103 Early Hintsвместо Server Push.