问题描述
我一直在为 Instagram 等照片共享应用编写 API,使用 Symfony2、FOSRESTBundle 和 Vichuploader 进行文件上传.
I have been coding an API for a photo sharing app like Instagram using Symfony2, FOSRESTBundle, and Vichuploader for file uploads.
我能够处理 GET 和 POST 请求,但我找不到如何附加到 POST 请求的示例,即实际图像,因此在我的情况下,Vichuploader 可以抓取它并帮助我解决文件上传.
I'm able to work around GET and POST requests, but I can't find an example of how to attach to a POST request, the actual image so that in my case, Vichuploader can grab it and help me out with the file upload.
顺便说一句,我可以使用通过使用正常形式提到的堆栈上传文件而不会出现问题.
By the way, I can upload a file without issue using the stack mentioned through the use of a normal form.
推荐答案
我一直在寻找关于完全相同问题的解决方案.这是我所做的.
I have been looking for a solution about the exact same problem. Here is what I did.
首先让我解释一下我的限制.我希望我的 API 是完整的 JSON 并利用 HTTP 协议(标头、方法等).我选择使用:
First let me explain my constraints. I wanted my API to be full JSON and to take power of the HTTP protocol (headers, methods, etc.). I chose to use:
- Symfony2 表示几乎为您完成了一切,只需编写您的业务逻辑".
- Doctrine2 因为默认情况下与 Symfony2 一起使用,并提供一种通过更改一行来与最流行的 DBMS 集成的方法.
- FOSRestBundle 用于处理我的 API 的 REST 部分(使用注释、正文侦听器、使用 JMSSerializer 支持自动格式化响应等功能发挥最大作用).
- KnpGaufretteBundle,因为我希望能够快速更改存储 blob 文件的方式.
设想的第一个解决方案:base64
我的第一个想法是,因为我每次都在考虑 JSON,所以将所有传入的图像编码为 base64,然后在我的 API 中对其进行解码并存储它们.
My first thought, because I was thinking JSON everytime, was to encode all the incoming images in base64, then decode them inside my API and store them.
此解决方案的优点是您可以将图像与其他数据一起传递.例如,在一次 API 调用中上传整个用户的个人资料.但是我读到在 base64 中编码图像使它们增长了初始大小的 33%.我不希望我的用户在发送 3 张图片后失去移动数据.
The advantage with this solution is that you can pass images along with other data. For instance upload a whole user's profile in one API call. But I read that encoding images in base64 make them grow by 33% of their initial size. I did not wanted my users to be out of mobile data after sending 3 images.
设想的第二种解决方案:表格
然后我想使用如上所述的表格.但我不知道我的客户如何同时发送 JSON 数据(例如 {"last_name":"Litz"}
)和图像数据(例如 image/png
一个).我知道您可以处理 Content-Type: multipart/form-data
但仅此而已.
Then I thought using forms as described above. But I did not know how my clients could send both JSON data (for instance {"last_name":"Litz"}
) and image data (for instance image/png
one). I know that you can deal with an Content-Type: multipart/form-data
but nothing more.
另外,我从一开始就没有在我的 API 中使用表单,我希望它在我的所有代码中都是统一的.[迷你hoho,我刚刚发现的东西,here]
Plus I was not using forms in my API since the beginning and I wanted it to be uniform in all my code. [mini-edit: hoho, something I just discovered, here]
第三个也是最后一个解决方案:使用 HTTP..
然后,有一天晚上,启示.我正在使用 Content-Type: application/json
发送 JSON 数据.为什么不使用 image/*
发送图像?如此简单,以至于我在提出这个想法之前搜索了几天.我就是这样做的(简化代码).假设用户正在使用 Content-Type: image/*
Then, one night, the revelation. I'm using Content-Type: application/json
for send JSON data. Why not use image/*
to send images? So easy that I searched for days before coming with this idea. This is how I did it (simplified code). Let suppose that the user is calling PUT /api/me/image
with a Content-Type: image/*
UserController::getUserImageAction(Request $request) - 捕获请求
UserController::getUserImageAction(Request $request) - Catching the Request
// get the service to handle the image
$service = $this->get('service.user_image');
$content = $request->getContent();
$userImage = $service->updateUserImage($user, $content);
// get the response from FOSRestBundle::View
$response = $this->view()->getResponse();
$response->setContent($content);
$response->headers->set('Content-Type', $userImage->getMimeType());
return $response;
UserImageService::updateUserImage($user, $content) - 业务逻辑(我把所有东西放在这里是为了更容易阅读)
UserImageService::updateUserImage($user, $content) - Business Logic (I put everything here to be simplier to read)
// Create a temporary file on the disk
// the temp file will be delete at the end of the script
// see http://www.php.net/manual/en/function.tmpfile.php
$file = tmpfile();
if ($file === false)
throw new \Exception('File can not be opened.');
// Put content in this file
$path = stream_get_meta_data($file)['uri'];
file_put_contents($path, $content);
// the UploadedFile of the user image
// referencing the temp file (used for validation only)
$uploadedFile = new UploadedFile($path, $path, null, null, null, true);
// the UserImage to return
$userImage = $user->getUserImage();
if (is_null($userImage))
{
$userImage = new UserImage();
$userImage->setOwner($user);
// auto persist with my configuration
// plus generation of a unique ID that allows
// me to retrieve the image at anytime
$userImage->setKey(/*random string*/);
}
// fill the UserImage properties
$userImage->setImage($uploadedFile);
$userImage->setMimeType($uploadedFile->getMimeType());
/** @var ConstraintViolationInterface $validationError */
if (count($this->getValidator()->validate($userImage)) > 0)
throw new \Exception('Validation');
// if no error we can write the file definitively
// [KnpGaufretteBundle code to store on disk]
// [use the UserImage::key to store]
$this->getEntityManager()->flush();
return $userImage;
这篇关于使用 Symfony2 & 通过 API 上传图像文件FOSRESTBundle的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!