Fosrestbundle主体在多部分请求时为空


Fosrestbundle body empty when multipart request

在下面的代码中,我希望$request->getContents()获得HTTP请求的正文内容。当发送非多部分请求时,这与预期的一样工作,但当使用多部分请求的时候,$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测试,这是有效的,尽管当使用PostmanAdvanced Rest Client来模拟请求时,主体似乎又是空的。我仔细检查了这一点,以使用调试器将两个模拟请求作为PHPUnit运行。结果是,实际上,当通过Rest客户端模拟时,主体是空的,而当通过PHPUnit运行时,主体不是空的。

我使用的测试用例:

张贴网址:

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.net上的php://包装:

注意:在PHP 5.6之前,一个流是用php://input只能读取一次;流不支持查找操作。但是,根据SAPI的实现,可能会打开另一个php://input流并重新开始读取。只有在保存了请求正文数据的情况下,才可能执行此操作。通常,POST请求是这种情况,但其他请求方法(如PUT或PROPFIND)则不然。

因此,请更新您的PHP版本,或者确保只读取一次输入。

您可以在fos_rest.decoder_provider解码后在$request->files->all()中找到上传的文件。