В приведенном ниже коде я ожидаю, что $request->getContents()
получит содержимое тела HTTP
запроса. При отправке не multipart-запроса это работает так, как ожидалось, но при использовании многочастных запросов переменная $body
остается пустой.
public function postDebugAction(Request $request) { $body = $request->getContent(); if (empty($body)) { throw new \Exception('Body empty.'); } return $this->view(array(), 201); }
Прочитав этот вопрос и ответ, я добавил слушателя тела.
<?php namespace VSmart\ApiBundle\Listener; use FOS\RestBundle\EventListener\BodyListener as BaseBodyListener; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use FOS\RestBundle\Decoder\DecoderProviderInterface; class BodyListener extends BaseBodyListener { /** * @var DecoderProviderInterface */ private $decoderProvider; /** * @param DecoderProviderInterface $decoderProvider Provider for fetching decoders */ public function __construct(DecoderProviderInterface $decoderProvider) { $this->decoderProvider = $decoderProvider; } /** * {@inheritdoc} */ public function onKernelRequest(GetResponseEvent $event) { $request = $event->getRequest(); if (strpos($request->headers->get('Content-Type'), 'multipart/form-data') !== 0) { return; } $format = 'json'; if (!$this->decoderProvider->supports($format)) { return; } $decoder = $this->decoderProvider->getDecoder($format); $iterator = $request->request->getIterator(); $request->request->set($iterator->key(), $decoder->decode($iterator->current(), $format)); } }
Согласно моему тесту PHPUnit, это работало, хотя при использовании Postman
и Advanced Rest Client
для имитации запроса тело кажется пустым снова. Я дважды проверил это, чтобы запускать как симулирующие запросы, так и PHPUnit с отладчиком. Результатом является то, что на самом деле тело пустое при моделировании через клиент Rest, а не пустое при запуске через PHPUnit.
В тестовом примере я использовал:
POST url:
http://localhost/EntisServer/web/app_dev.php/api2/debug
Заголовки:
Authorization: Bearer ZGYzYjY1YzY4MGY3YWM3OTFhYTI4Njk3ZmI0NmNmOWZmMjg5MDFkYzJmOWZkOWE4ZTkyYTRmMGM4NTE1MWM0Nw Content-Type: multipart/form-data; boundary=-----XXXXX
Содержание:
-----XXXXX Content-Disposition: form-data; name="json" Content-Type: application/json; charset=utf-8 { "blabla": 11 } -----XXXXX Content-Disposition: form-data; name="q_3101"; filename="image.jpg" Content-Type: image/jpeg contents of a file... -----XXXXX--
ОБНОВЛЕНИЕ Я не знал, прошел ли я через отладчик без использования BodyListener
. Когда я сделал результат, это точно то же самое. Таким образом, без BodyListener
случай PHPUnit получает тело, хотя симулированный запрос все еще пуст.
См. php://
wrappers на php.net:
Примечание. До PHP 5.6 поток, открытый с помощью ввода php: //, может быть прочитан только один раз; поток не поддерживал операции поиска. Однако, в зависимости от реализации SAPI, может быть возможно открыть другой поток ввода php: // и перезапустить чтение. Это возможно только в том случае, если данные тела запроса сохранены. Как правило, это относится к запросам POST, но не к другим методам запроса, таким как PUT или PROPFIND.
Поэтому обновите свою версию PHP или убедитесь, что вы только читаете ввод один раз.