PSR-7: getParsedBody() против getBody()

Сценарий 1: отправка x-www-form-urlencoded данных

POST /path HTTP/1.1
Content-Type: application/x-www-form-urlencoded

foo=bar

Выполнение print_r($request->getParsedBody()); возвращает нормально:

Array
(
    [foo] => bar
)

Выполнение print_r($request->getBody()->getContents()); возвращает строку foo=bar


Сценарий 2: отправка application/json данных

POST /path HTTP/1.1
Content-Type: application/json

{
    "foo": "bar"
}

Выполнение print_r($request->getParsedBody()); возвращает пустой массив. Array ( )

Но запуск print_r($request->getBody()->getContents()); возвращает нормально:

{"foo":"bar"}


Это ожидаемое поведение?

Это означает, что если мы отправляем данные x-www-form-urlencoded, мы должны использовать getParsedBody().

Хотя getBody()->getContents() следует использовать, если мы отправляем application/json?


Дополнительная информация:

Объект запроса создается с помощью:

$request = \Laminas\Diactoros\ServerRequestFactory::fromGlobals(
        $_SERVER, $_GET, $_POST, $_COOKIE, $_FILES
);

person IMB    schedule 06.02.2020    source источник
comment
1) Какую библиотеку PSR-7 вы используете - может быть Zend diactoros? 2) Для каждого сценария вы должны предоставить код для создания объекта ServerRequest. 3) К Сценарию 1: Пробовали ли вы также активировать метод StreamInterface::__toString примерно так: $content = (string) ($request->getBody()); echo $content;? Я спрашиваю об этом, потому что реализация метода StreamInterface::__toString ДОЛЖНА пытаться перейти к началу потока перед чтением данных, тогда как StreamInterface::getContents только возвращает оставшееся содержимое в строка.   -  person dakis    schedule 09.02.2020
comment
@dakis На самом деле сценарий 1, кажется, действительно возвращает строку foo=bar при использовании $request->getBody()->getContents(). Я обновил сценарии. Также включен способ создания объекта запроса.   -  person IMB    schedule 09.02.2020


Ответы (1)


Тело сообщения:

В библиотеке PSR-7 тело сообщения абстрагируется классом StreamInterface. Любая реализация этого интерфейса ДОЛЖНА заключать в себе поток PHP и, конечно же, , должен обеспечивать надлежащую функциональность для выполнения определенных операций чтения/записи/поиска на нем. PHP предоставляет список потоков ввода-вывода, из которых php://input подходит для поставленной задачи.

php://input — это поток только для чтения, который позволяет вам считывать необработанные данные из тела запроса.
php://input недоступен с enctype=multipart/form-data.

В этом контексте, когда выполняется запрос к серверу, данные тела запроса (независимо от его типа данных) автоматически записываются в поток php://input в необработанном формате (строка). Информацию можно позже прочитать из него, вызвав StreamInterface::getContents, StreamInterface::__toString или StreamInterface::read (которые, вероятно, использовали бы stream_get_contents() или подобное в своей реализации).

Проанализированное тело:

Что касается PSR-7, анализируемое тело является характеристикой приложений, в которых PHP используется в качестве серверного приложения для выполнения HTTP-запросов (по сравнению с приложений, где PHP используется в качестве HTTP-клиента) — см. Краткий обзор метадокумента PSR-7. Таким образом, проанализированное тело является компонентом только ServerRequestInterface.

Проанализированное тело (читайте комментарии ServerRequestInterface::getParsedBody и ServerRequestInterface::withParsedBody) рассматривается как представление необработанных данных (строки), сохраненных в потоке php://input (в результате выполнения запроса) в проанализированной форме ( массив или объект). Например, $_POST переменная содержит проанализированное тело запроса POST в соответствии с условиями, представленными ниже.

Подходящие варианты использования:

Если выполняется запрос POST, а заголовок Content-Type равен application/x-www-form-urlencoded (например, при отправке обычной HTML-формы), содержимое тела запроса автоматически сохраняется как в поток php://input (сериализованный), так и в переменную $_POST (массив). Таким образом, в контексте PSR-7 вызов как StreamInterface::getContents (или StreamInterface::__toString, так и StreamInterface::read) и ServerRequestInterface::getParsedBody вернет допустимые значения.

Если выполняется запрос POST и заголовок Content-Type имеет значение multipart/form-data (например, при выполнении загрузки файла(ов), то содержимое тела запроса НЕ сохраняется в поток php://input, а только в переменную $_POST (массив ). Таким образом, в контексте PSR-7 только вызов ServerRequestInterface::getParsedBody вернет допустимое значение.

Если выполняется POST-запрос и заголовок Content-Type имеет значение, отличное от двух представленных выше (например, application/json или text/plain; charset=utf-8), содержимое тела запроса сохраняется только в поток php://input. Итак, в контексте PSR-7 только вызов StreamInterface::getContents (или StreamInterface::__toString, или StreamInterface::read) вернет допустимое значение.

Ресурсы:

person dakis    schedule 09.02.2020