我有一个 Symfony 项目,由多个微服务组成,每个微服务位于不同的存储库中,还有一个充当 API 网关的微服务,前端通过这些微服务进行调用,以便通过令牌验证用户身份验证和对资源的访问权限在向 Guzzle 提出请求之前有疑问。
我目前负责通过 minIO 链接到 S3 存储桶上的文档管理(上传、下载等)的微服务。
这是我的微服务的控制器,以及它调用的服务:
<?php
namespace App\Controller;
use App\Service\UploadFileService;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
class UploadFileController extends AbstractController
{
private UploadFileService $uploadFileService;
public function __construct(UploadFileService $uploadFileService)
{
$this->uploadFileService = $uploadFileService;
}
#[Route('/api/v1/upload_files', name: 'upload_files', methods:['POST'])]
public function uploadFiles(Request $request): JsonResponse
{
return $this->uploadFileService->uploadFiles($request);
}
}
<?php
namespace App\Service;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;
use Aws\S3\S3Client as AmazonS3;
class UploadFileService extends AbstractController
{
public function uploadFiles(Request $request): JsonResponse
{
try {
$files = $request->files->all('files');
$urls = $request->request->all('urls');
//On vérifie qu'il y a des fichiers, et qu'il y a autant d'url que de fichiers
if (empty($files) || count($files) !== count($urls)) {
return $this->json(['error' => 'Invalid files or URLs.']);
}
//On se connecte à minIo
$s3 = new AmazonS3([
'version' => 'latest',
'region' => 'eu',
'endpoint' => $_ENV['S3_URL'],
'use_path_style_endpoint' => true,
'credentials' => [
'key' => $_ENV['S3_ACCESS_KEY'],
'secret' => $_ENV['S3_SECRET_KEY']
],
]);
$results = [];
foreach ($files as $index => $file) {
//On vérifie la validité du fichier
if (!$file instanceof UploadedFile || !$file->isValid()) {
return $this->json(['error' => 'Invalid file.']);
}
$fileContent = fopen($file->getPathname(), 'rb');
// On utilise finfo pour détecter le type MIME pour l'enregistrer sous le bon format
$finfo = new \finfo(FILEINFO_MIME_TYPE);
$mimeType = $finfo->file($file->getPathname());
//On l'enregistre
$result = $s3->putObject([
'Bucket' => 'documents',
'Key' => $urls[$index],
'Body' => $fileContent,
'ContentType' => $mimeType,
]);
fclose($fileContent);
$results[] = $result['@metadata']['statusCode'];
}
return $this->json(['results' => $results]);
} catch (\Exception $ex) {
return $this->json(['Exception' => $ex->getMessage()], 400);
}
}
}
此代码是实用的,可以直接调用这种类型的 Postman:
现在当我尝试使用Gateway API时出现了问题,其代码如下:
<?php
namespace App\Controller\DocumentService;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use App\Security\AccessControl;
#[Route('/api/v1/syndicatDashboard/{coproprieteId}/upload', name:'app_document_upload', methods:['POST'])]
class UploadFileController extends AbstractController
{
private AccessControl $accessControl;
public function __construct(AccessControl $accessControl)
{
$this->accessControl = $accessControl;
}
public function __invoke(string $coproprieteId, Request $request): JsonResponse
{
try {
$this->accessControl->getVoteCopropriete($this->getUser()->getId(),$this->getUser()->getRoles(), $coproprieteId);
$url = $_ENV['GESTION_DOCUMENTS']."/api/v1/upload_files";
$client = new Client();
$response = $client->post($url, [
'body' => $request->getContent(),
'headers' => $request->headers->all(),
]);
return $this->json(json_decode($response->getBody()->getContents()), 200);
} catch (GuzzleException $e) {
if (str_contains($e->getMessage(), "cURL error 7")) {
throw new \Exception($e->getMessage());
}
return $this->json(json_decode($e->getResponse()->getBody()->getContents()), $e->getCode());
} catch (\Throwable $e) {
return $this->json(["Exception" => $e->getMessage()], $e->getCode());
}
}
}
我正在执行链接到令牌和
$coproprieteId
字符串的检查,但对于“正文”,我只想检索它并将其发送到我的微服务,但如果我返回 $request-\>getContent()
它是空的。
我也尝试过直接发送
$request-\>request-\>all('urls')
并且它有效,但是如果我在 API 网关中显示它,我无法发送 $request-\>files-\>all('files'):
我已经得到了我的文件,但在微服务端该值变为空。
所以我的问题是:如何获取正文并将其发送到我的微服务?
检查 guzzle 多部分文档以使用 guzzle 发送文件。
简单的例子
$client->post($url, [
RequestOptions::MULTIPART => [
[
'name' => 'var_name',
'contents' => 'var_value',
],
[
'name' => 'avatar',
'contents' => file_get_contents($request->file('avatar')->getPathname()),
'filename' => 'avatar.' . $request->file('avatar')->getClientOriginalExtension()
],
[
'name' => 'avatar2',
'contents' => file_get_contents($request->file('avatar2')->getPathname()),
'filename' => 'avatar2.' . $request->file('avatar2')->getClientOriginalExtension()
],
]
]);