我如何使用 Guzzle 将 Symfony 请求传递给另一个控制器

问题描述 投票:0回答:1

我有一个 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:

postman call

现在当我尝试使用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'):
我已经得到了我的文件,但在微服务端该值变为空。

所以我的问题是:如何获取正文并将其发送到我的微服务?

php symfony guzzle api-gateway
1个回答
0
投票

检查 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()
        ],
    ]
]);
© www.soinside.com 2019 - 2024. All rights reserved.