PSR-7: Интерфейс HTTP Сообщений

Этот документ описывает общие интерфейсы для представления HTTP сообщений, как описано в RFC 7230 и RFC 7231, и URI для использования с сообщениями HTTP, как описано в RFC 3986.

HTTP-сообщения являются основой веб-разработки. Веб-браузеры и HTTP-клиенты, такие как cURL, создают HTTP-запрос, который отправляется на веб-сервер, предоставляющий HTTP-ответ. Серверный код получает HTTP-запрос и возвращает ответное сообщение HTTP.

Сообщения HTTP обычно абстрагируются от конечного потребителя, но как разработчики, мы как правило должны знать, как они структурированы и как получить доступ к ним или манипулировать ими для выполнения наших задач, будь то выполнение запроса к HTTP API или обработка входящего запроса.

Каждое сообщение HTTP-запроса имеет определенную форму:

POST /path HTTP/1.1
Host: example.com
 
foo=bar&baz=bat

Первая строка запроса является «строкой запроса» и содержит по порядку метод HTTP-запроса, целевой объект запроса (обычно либо абсолютный URI, либо путь на веб-сервере) и версию протокола HTTP. Далее следует один или несколько заголовков HTTP, пустая строка и текст сообщения.

Ответные сообщения HTTP имеют схожую структуру:

HTTP/1.1 200 OK
Content-Type: text/plain
 
This is the response body

Первая строка является «строкой состояния» и содержит по порядку версию протокола HTTP, код состояния HTTP и «формулировка причины» - удобочитаемое описание кода состояния. Как и сообщение запроса, за ним следует один или несколько заголовков HTTP, пустая строка и тело сообщения.

Интерфейсы, описанные в этом документе, являются абстракциями вокруг HTTP-сообщений и составляющих их элементов.

Ключевые слова 'ДОЛЖНЫ', 'НЕ ДОЛЖНЫ', 'ТРЕБУЕТСЯ', 'НУЖНО', 'НЕ НУЖНО', 'СЛЕДУЕТ', 'НЕ СЛЕДУЕТ', 'РЕКОМЕНДУЕТСЯ', 'МОЖЕТ' и 'НЕОБЯЗАТЕЛЬНО' в этом документе должны толковаться так, как описано в RFC 2119.

Ссылки

1. Описание

1.1 Сообщения

HTTP-сообщение - это либо запрос от клиента к серверу, либо ответ от сервера клиенту. Это описание определяет интерфейсы для сообщений HTTP Psr\Http\Message\RequestInterface и Psr\Http\Message\ResponseInterface соответственно.

Оба интерфейса Psr\Http\Message\RequestInterface и Psr\Http\Message\ResponseInterface расширяют Psr\Http\Message\MessageInterface. В то время как интерфейс Psr\Http\Message\MessageInterface МОЖЕТ быть реализован напрямую, разработчики ДОЛЖНЫ реализовать интерфейсы Psr\Http\Message\RequestInterface и Psr\Http\Message\ResponseInterface.

В дальнейшем пространство имен Psr\Http\Message будет опущено при обращении к этим интерфейсам.

1.2 HTTP-Заголовки

Имена полей заголовка без учета регистра

HTTP-сообщения содержат имена полей заголовка без учета регистра. Заголовки извлекаются по имени из классов, реализующих интерфейс MessageInterface без учета регистра. Например, извлечение заголовка foo вернет тот же результат, что и извлечение заголовка FoO. Аналогично, установка заголовка Foo перезапишет любое ранее установленное значение заголовка в foo.

$message = $message->withHeader('foo', 'bar');
 
echo $message->getHeaderLine('foo');
// Выведет: bar
 
echo $message->getHeaderLine('FOO');
// Выведет: bar
 
$message = $message->withHeader('fOO', 'baz');
echo $message->getHeaderLine('foo');
// Выведет: baz

Несмотря на то, что заголовки могут быть получены без учета регистра, исходный регистр ДОЛЖЕН быть сохранен реализацией, в частности, при получении с помощью getHeaders().

Несоответствующие HTTP-приложения могут зависеть от определенного случая, поэтому пользователю полезно иметь возможность диктовать регистр HTTP-заголовков при создании запроса или ответа.

Заголовки с несколькими значениями

Чтобы разместить заголовки с несколькими значениями, но при этом обеспечить удобство работы с заголовками в виде строк, заголовки могут быть извлечены из экземпляра MessageInterface в виде массива или строки. Используйте метод getHeaderLine() для получения значения заголовка в виде строки, содержащей все значения заголовка без учета регистра имени, перечисленныые через запятую. Используйте getHeader(), чтобы по имени заголовка, получить массив всех значений конкретного заголовка нечувствительного к регистру.

$message = $message
    ->withHeader('foo', 'bar')
    ->withAddedHeader('foo', 'baz');
 
$header = $message->getHeaderLine('foo');
// $header содержит: 'bar,baz'
 
$header = $message->getHeader('foo');
// ['bar', 'baz']

Примечание: не все значения заголовка могут быть объединены с помощью запятой (например, Set-Cookie). При работе с такими заголовками потребители классов основанных на MessageInterface ДОЛЖНЫ полагаться на метод getHeader() для извлечения таких многозначных заголовков.

Заголовок Host

В запросах, заголовок Host, обычно отражает хостовую часть от URI, а также хост, используемый при установлении TCP-соединения. Однако, спецификация HTTP для каждого из них позволяет заголовку Host отличаться.

Если заголовок Host не установлен, то во время создания, реализация ДОЛЖНА попытаться установить заголовок Host из предоставленного URI.

RequestInterface::withUri() по умолчанию заменит заголовок Host возвращаемого запроса, на заголовок c Host соответствующего части хоста переданного из UriInterface.