使用 Uppy/Laravel/Vue 上传多部分文件

Uploading Multipart Files with Uppy/Laravel/Vue

我正在使用 Uppy's Vue components 来处理上传大文件,但我无法正常工作。

我遵循了 Janko here 的建议,其中涉及在 Uppy 中设置 companionUrl 以指向我的服务器,然后编写必要的 routes/functions处理请求。

一切正常,直到我尝试启动 AWS“completeMultipartUpload”调用。

$result = $client->completeMultipartUpload([
    'Bucket'          => 'bucket-name',
    'Key'             => $key,
    'UploadId'        => $uploadId,
    'MultipartUpload' => [
        'Parts' => $formattedParts,
    ],
]);

我收到以下错误:

"Error executing "CompleteMultipartUpload" on "https://bucket-name.s3.amazonaws.com/NewProject.png?uploadId=nlWLdbNgB9zgarpLBXnj17eOIGAmQM_xyBArymtwdM71fhbFvveggDmL6fz4blz.B95TLhMatDvodbMb5p2ZMKqdlLeLFoSW1qcu33aRQTlt6NbiP_dkDO90DFO.pWGH"; AWS HTTP error: Client error: `POST https://bucket-name.s3.amazonaws.com/NewProject.png?uploadId=nlWLdbNgB9zgarpLBXnj17eOIGAmQM_xyBArymtwdM71fhbFvveggDmL6fz4blz.B95TLhMatDvodbMb5p2ZMKqdlLeLFoSW1qcu33aRQTlt6NbiP_dkDO90DFO.pWGH` resulted in a `400 Bad Request` response:
    <Error><Code>InvalidPart</Code><Message>One or more of the specified parts could not be found.  The part may not have be (truncated...)
    InvalidPart (client): One or more of the specified parts could not be found.  The part may not have been uploaded, or the specified entity tag may not match the part's entity tag. - <Error><Code>InvalidPart</Code><Message>One or more of the specified parts could not be found.  The part may not have been uploaded, or the specified entity tag may not match the part's en"

我认为问题在于我尝试将找到的 JS here 翻译成 PHP,但尽管它返回 URL,但它不正确。显着的区别是我没有传递“UploadId”或“PartNumber”。

我搜索了 AWS 文档、Google、Whosebug、Ask Jeeves 等,但找不到 PHP 等同于 "getSignedUrl" method

public function signPartUpload(Request $request, $uploadId, $partNumber)
{
    $client = new S3Client([
        'version' => 'latest',
        'region'  => 'us-east-1',
    ]);

    $key = $request->has('key') ? $request->get('key') : null;

    if (!is_string($key)) {
        return response()->json(['error' => 's3: the object key must be passed as a query parameter. For example: "?key=abc.jpg"'], 400);
    }

    if (!intval($partNumber)) {
        return response()->json(['error' => 's3: the part number must be a number between 1 and 10000.'], 400);
    }

    //Creating a presigned URL
    $cmd = $client->getCommand('PutObject', [
        'Bucket' => 'bucket-name',
        'Key' => $key
    ]);

    $response = $client->createPresignedRequest($cmd, '+20 minutes');
    $presignedUrl = (string)$response->getUri();

    return response()->json(['url' => $presignedUrl]);
}

如有任何帮助,我们将不胜感激!

我发现 PHP 等同于 getSignedUrl 方法。

$command = $this->client->getCommand('UploadPart', [
    'Bucket'        => $this->bucket,
    'Key'           => $key,
    'PartNumber'    => $partNumber,
    'UploadId'      => $uploadId,
    'Body'          => '',
]);

这是我的解决方案:

/**
 * Create a pre-signed URL for parts to be uploaded to.
 * @param Request $request
 * @param string $uploadId
 * @param int $partNumber
 * @return JsonResponse
 */
public function signPartUpload(Request $request, string $uploadId, int $partNumber)
{
    $key = $request->has('key') ? $request->get('key') : null;

    // Check key
    if (! is_string($key)) {
        return response()->json(['error' => 's3: the object key must be passed as a query parameter. For example: "?key=abc.jpg"'], 400);
    }

    // Check part number
    if (! intval($partNumber)) {
        return response()->json(['error' => 's3: the part number must be a number between 1 and 10000.'], 400);
    }

    // Create the upload part command and get the pre-signed URL
    try {
        $command = $this->client->getCommand('UploadPart', [
            'Bucket'        => $this->bucket,
            'Key'           => $key,
            'PartNumber'    => $partNumber,
            'UploadId'      => $uploadId,
            'Body'          => '',
        ]);

        $presignedUrl = $this->client->createPresignedRequest($command, '+20 minutes');
    } catch (Exception $e) {
        return response()->json(['error' => $e->getMessage()], 400);
    }

    // Convert the pre-signed URL to a string
    $presignedUrlString = (string) $presignedUrl->getUri();

    return response()->json(['url' => $presignedUrlString]);
}