API Platform中Multipart/Form-Data反序列化问题求助
解决API Platform + Symfony处理multipart/form-data反序列化错误
错误原因
你遇到的Deserialization for the format "multipart" is not supported错误有两个核心原因:
- API Platform默认序列化系统不支持直接将
multipart/form-data请求反序列化为实体对象,即便在配置中声明了multipart格式,也需要结合文件上传组件实现特定逻辑。 - 你自定义的
/api/messagesPOST路由和API Platform为Message实体自动生成的路由冲突,请求被API Platform的处理管道接管,而非进入你写的控制器代码,从而触发了反序列化错误。
解决方案一:使用API Platform原生文件上传(推荐)
遵循API Platform规范,结合VichUploaderBundle实现文件上传,无需自定义控制器:
1. 安装依赖
composer require vich/uploader-bundle
2. 修改Message实体
namespace App\Entity; use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\Post; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\HttpFoundation\File\File; use Symfony\Component\Serializer\Annotation\Groups; use Vich\UploaderBundle\Mapping\Annotation as Vich; #[ORM\Entity] #[ApiResource( normalizationContext: ['groups' => ['message:read']], denormalizationContext: ['groups' => ['message:write']], operations: [ new Post( uriTemplate: '/api/messages', openapiContext: [ 'requestBody' => [ 'content' => [ 'multipart/form-data' => [ 'schema' => [ 'type' => 'object', 'properties' => [ 'description' => ['type' => 'string'], 'keywords' => ['type' => 'string'], 'category' => ['type' => 'string', 'format' => 'iri'], 'audioFile' => [ 'type' => 'string', 'format' => 'binary' ] ] ] ] ] ] ] ) ] )] #[Vich\Uploadable] class Message { #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column] #[Groups(['message:read'])] private ?int $id = null; #[ORM\Column(length: 255)] #[Groups(['message:read', 'message:write'])] private ?string $description = null; #[ORM\Column(length: 255)] #[Groups(['message:read', 'message:write'])] private ?string $keywords = null; #[ORM\ManyToOne(targetEntity: Category::class)] #[ORM\JoinColumn(nullable: false)] #[Groups(['message:read', 'message:write'])] private ?Category $category = null; #[ORM\Column(length: 255, nullable: true)] #[Groups(['message:read'])] private ?string $audioFileName = null; #[Vich\UploadableField(mapping: 'message_audio', fileNameProperty: 'audioFileName')] #[Groups(['message:write'])] private ?File $audioFile = null; // Getter & Setter public function getId(): ?int { return $this->id; } public function getDescription(): ?string { return $this->description; } public function setDescription(string $description): self { $this->description = $description; return $this; } public function getKeywords(): ?string { return $this->keywords; } public function setKeywords(string $keywords): self { $this->keywords = $keywords; return $this; } public function getCategory(): ?Category { return $this->category; } public function setCategory(?Category $category): self { $this->category = $category; return $this; } public function getAudioFileName(): ?string { return $this->audioFileName; } public function setAudioFileName(?string $audioFileName): self { $this->audioFileName = $audioFileName; return $this; } public function getAudioFile(): ?File { return $this->audioFile; } public function setAudioFile(?File $audioFile): self { $this->audioFile = $audioFile; return $this; } }
3. 配置VichUploaderBundle
在config/packages/vich_uploader.yaml添加:
vich_uploader: db_driver: orm mappings: message_audio: uri_prefix: /uploads/audio upload_destination: '%kernel.project_dir%/public/uploads/audio' namer: Vich\UploaderBundle\Naming\UniqidNamer
4. 移除自定义控制器
API Platform会自动处理POST请求,包括multipart/form-data的解析和文件上传,你的Angular服务代码无需修改。
解决方案二:保留自定义控制器,避免API Platform拦截
如果你坚持使用自定义控制器,需要确保请求直接进入你的代码:
1. 禁用Message实体的自动路由
在Message实体上添加注解,关闭API Platform自动生成的路由:
#[ApiResource(operations: [])]
2. 修改自定义控制器路由
添加优先级和ApiIgnore注解,确保路由优先且被API Platform忽略:
namespace App\Controller; use App\Entity\Message; use ApiPlatform\Core\Bridge\Symfony\Annotation\ApiIgnore; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Doctrine\ORM\EntityManagerInterface; class MessageController extends AbstractController { #[ApiIgnore] #[Route('/api/messages', name: 'api_message_create', methods: ['POST'], priority: 10)] public function create(Request $request, EntityManagerInterface $entityManager): Response { // 原控制器代码不变 } }
这样请求会直接进入你的控制器,绕过API Platform的序列化管道,不会触发反序列化错误。
内容的提问来源于stack exchange,提问作者fatimazahra
相关产品推荐
相关产品推荐

