Mal*_*chi 9 rest symfony fosrestbundle
我正在使用FOSRestBundle构建API,并且我正处于需要实现创建包含二进制数据的新实体的处理阶段.
按照发送二进制数据和REST API请求
概述的方法,multipart/form-data由于Base64需要增加约33%的带宽,因此发送数据对于我们的实现感觉最实用.
题
如何配置REST端点以处理请求中的文件,并在发送数据时对JSON编码实体执行验证multipart/form-data?
当刚刚发送原始JSON时,我一直在使用Symfony的表单handleRequest方法来执行针对自定义的验证FormType.例如:
$form = $this->createForm(new CommentType(), $comment, ['method' => 'POST']);
$form->handleRequest($request);
if ($form->isValid()) {
// Is valid
}
Run Code Online (Sandbox Code Playgroud)
我喜欢这种方法的原因是,我可以根据操作是更新(PUT)还是新操作(POST)来更多地控制实体的数量.
我知道Symfony的Request对象处理请求,以前JSON数据将是content变量,但现在键入request->parameters->[form key]文件bag(request->files)中的文件.
似乎没有干净的方法来检索表单数据的Content-Type而不解析原始请求.
如果您的API仅支持json输入,或者您可以添加自定义标头(请参阅下面的注释),则可以使用此解决方案:
首先,你必须实现自己的body_listener:
namespace Acme\ApiBundle\FOS\EventListener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use FOS\RestBundle\Decoder\DecoderProviderInterface;
class BodyListener
{
/**
* @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';
/*
* or, using a custom header :
*
* if (!$request->headers->has('X-Form-Content-Type')) {
* return;
* }
* $format = $request->getFormat($request->headers->get('X-Form-Content-Type'));
*/
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));
}
}
Run Code Online (Sandbox Code Playgroud)
然后在您的配置文件中:
services:
acme.api.fos.event_listener.body:
class: Acme\ApiBundle\FOS\EventListener\BodyListener
arguments:
- "@fos_rest.decoder_provider"
tags:
-
name: kernel.event_listener
event: kernel.request
method: onKernelRequest
priority: 10
Run Code Online (Sandbox Code Playgroud)
最后,你只需要打电话给handleRequest你的控制器.例如:
$form = $this->createFormBuilder()
->add('foo', 'text')
->add('file', 'file')
->getForm()
;
$form->handleRequest($request);
Run Code Online (Sandbox Code Playgroud)
使用此请求格式(form必须替换为您的表单名称):
POST http://xxx.xx HTTP/1.1
Content-Type: multipart/form-data; boundary="01ead4a5-7a67-4703-ad02-589886e00923"
Host: xxx.xx
Content-Length: XXX
--01ead4a5-7a67-4703-ad02-589886e00923
Content-Type: application/json; charset=utf-8
Content-Disposition: form-data; name=form
{"foo":"bar"}
--01ead4a5-7a67-4703-ad02-589886e00923
Content-Type: text/plain
Content-Disposition: form-data; name=form[file]; filename=foo.txt
XXXX
--01ead4a5-7a67-4703-ad02-589886e00923--
Run Code Online (Sandbox Code Playgroud)
在放弃并寻找具有单独的图像上传端点的替代选项之后。例如:
POST /comments
POST /comments/{id}/image
我发现已经有一个包提供了各种 RESTful 上传过程。其中之一是我最初希望能够multipart/form-data在提取文件时解析为实体的功能。
| 归档时间: |
|
| 查看次数: |
7086 次 |
| 最近记录: |