===== PSR-7: Интерфейс HTTP Сообщений =====
Этот документ описывает общие интерфейсы для представления HTTP сообщений, как описано в [[https://tools.ietf.org/html/rfc7230|RFC 7230]] и [[https://tools.ietf.org/html/rfc7231|RFC 7231]], и URI для использования с сообщениями HTTP, как описано в [[https://tools.ietf.org/html/rfc3986|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-сообщений и составляющих их элементов.
Ключевые слова 'ДОЛЖНЫ', 'НЕ ДОЛЖНЫ', 'ТРЕБУЕТСЯ', 'НУЖНО', 'НЕ НУЖНО', 'СЛЕДУЕТ', 'НЕ СЛЕДУЕТ', 'РЕКОМЕНДУЕТСЯ', 'МОЖЕТ' и 'НЕОБЯЗАТЕЛЬНО' в этом документе должны толковаться так, как описано в [[:MiklyxoMaklai:rus-PSR:blob:master:rfc2119|RFC 2119]].
[[#ссылки|Ссылки]]
* [[https://tools.ietf.org/html/rfc2119|RFC 2119]]
* [[https://tools.ietf.org/html/rfc3986|RFC 3986]]
* [[https://tools.ietf.org/html/rfc7230|RFC 7230]]
* [[https://tools.ietf.org/html/rfc7231|RFC 7231]]
=== 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]]
В запросах, заголовок ''Host'', обычно отражает хостовую часть от URI, а также хост, используемый при установлении TCP-соединения. Однако, спецификация HTTP для каждого из них позволяет заголовку ''Host'' отличаться.
Если заголовок ''Host'' не установлен, то во время создания, реализация ДОЛЖНА попытаться установить заголовок ''Host'' из предоставленного URI.
''RequestInterface::withUri()'' по умолчанию заменит заголовок ''Host'' возвращаемого запроса, на заголовок c ''Host'' соответствующего части хоста переданного из ''UriInterface''.