从 AWS s3 批量下载失败

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

这段代码直到几天前都运行良好。然而,我们注意到下载 40 个文件后就失败了。我不记得最近更改过任何配置参数。

尝试通过验证这些场景进行隔离:

  1. 不同的图像
  2. 不同的文件夹
  3. 不同的用户
  4. 不同的S3存储桶
  5. 不同的服务器 - 登台和生产 - 两者都出现问题
  6. 没有内存(存储和 RAM),预先指定的文件权限问题 网址可访问并且有足够的存储空间和内存可用 在服务器上

令人费解的是 - 为什么在第 40 个文件之后下载失败?客户端(浏览器)收到错误“无法下载 zip 文件。如果问题仍然存在,请使用高速互联网连接重试或联系支持人员!”。这是从 catch 块返回给客户端的响应。

当然,这个错误是可以修复的。但是,即使有更多文件,它也无法帮助用户下载超过 40 个文件。

  • 该过程是否有可能在下载文件之前转移到填充 $ImagesZip 数组?
  • 如果是这样,为什么每次都在 40 个文件之后失败?文件的大小可能不同,有些文件的大小可能需要更长/更短的时间。

我已经失去理智了。非常感谢任何帮助。

下面是经过净化的代码:

public function downloadZip(Request $request) { 

    $reqdata = $request->all();
    $ordref = @$reqdata['ordref'];
    $usrnumber = @$reqdata['usrnumber'];

    if (!$ordref || !$usrnumber) {
    //check if parameters passed valid
        echo json_encode($data);
        exit();
    } 

    $this->db = DB::table("orders AS o");
    $details = $this->db->select("o.photos", "o.ref", "o.id", "o.folder_id", "o.price","o.is_download")
            ->where(....)
            ->first();

    if (!$details) {
        return redirect("/");
    }

    //check if json is valid
    $images = $this->processphotos($details->photos);

    // find photo ids from DB        
    ....
    ....
    $dbimages = $this->getimagesbyids($imageids);

    $imageNames = [];
    foreach ($dbimages as $item) {
        $thumbName = $item->imgurl;
        array_push($imageNames, array('image' => $thumbName, 'category' => $item->category, 'id' => $item->id));
    }


    if (!$imageNames) {
    //return No images found error.

    }

    $zipimages = [];
    $public_dir = public_path() . DIRECTORY_SEPARATOR . 'downloads' . DIRECTORY_SEPARATOR;
    $zipimagesarray = array();
    $imagepatharray = explode("/", $imageNames[0]['image']);
    $imagename = end($imagepatharray);

    $ctr = 100;
    foreach ($imageNames as $row) {
        $imgtype = 'jpg';
        $prefix = $usrnumber.'_';
        $imagename = $prefix . $ctr . $imgtype;
        $signedurl = $this->getpresignedurl($row['image']);
        @ File::copy($signedurl, $public_dir . $imagename);

        array_push($zipimagesarray, array('path' => $public_dir, "image" => $imagename));
        $ctr++;
    }

    $imageZip = [];
    $certZip = [];
    foreach ($zipimagesarray as $imagePublic) {
        $path = explode(DIRECTORY_SEPARATOR,$imagePublic['path']);

        $zipImage = $imagePublic['path'] . $imagePublic['image'];
        array_push($imageZip, $zipImage);
    }

    try {
        $zipName = $usrnumber . date('G:i:s') . ".zip";

        Zipper::make(public_path('downloadOrder/' . $zipName))->add($imageZip)->close();

        File::delete($imageZip);
        $file = "/download/" . $zipName;

        $data['result'] = array();
        $data['result'] = url('/') . $file ;
        $data['statusCode'] = 200;
        $data['hasError'] = false;
        $data['message'] = "Images retrieval is successful.";
        return response($data)->header('Content-Type', 'application/json');
    } catch (\Exception $ex) {
        $data['result'] = array();
        $data['statusCode'] = 400;
        $data['hasError'] = true;
        $data['message'] = "Unable to download the zip file. Please retry on a high speed internet connection or contact support, if issue persists!";
        Log::error("Api::downloadZip - orderId: " . $data['Message'] . " " . $ex->getMessage());
        return response($data)->header('Content-Type', 'application/json');
    }
}

function getpresignedurl($key, $s3Client = null) {

$s3_env = [];
$Bucket = "xxxxx";

if (is_null($s3Client)) { 
   $s3_env = array('region' => config('aws.AWS_REGION'),
       'credentials' => ['key' => config('aws.AWS_ACCESS_KEY_ID'), 'secret' => config('aws.AWS_SECRET_ACCESS_KEY')]);
   $s3Client = \App::make('aws')->createClient('s3', $s3_env);
}

//Creating a presigned URL
$cmd = $s3Client->getCommand('GetObject', [
    'Bucket' => $Bucket,
    'Key' => $key
]);

$request = $s3Client->createPresignedRequest($cmd, '+30 minutes');
$signedurl = (string) $request->getUri();
return $signedurl;
}
amazon-web-services file amazon-s3 laravel-5 php-7.1
1个回答
0
投票

嗯,这不是所报告问题的确切解决方案。

我已经通过实施全新的方法来解决这个问题。引入了新方法

downloadFile
并使用 AWS SDK
GetObject
命令下载文件。即使
saveAs
中的
GetObject
参数也无法解决问题。此解决方案 getObject with SaveAs 在 sdk v3 中不起作用 有帮助。

function downloadFile($key, $destination, $s3Client = null) {
     $s3_env = [];
     $Bucket = "xxxxx";

     try {
        if (is_null($s3Client)) { 
            $s3_env = array('region' => config('aws.AWS_REGION'),
                'credentials' => ['key' => config('aws.AWS_ACCESS_KEY_ID'), 'secret' => config('aws.AWS_SECRET_ACCESS_KEY')]);
            $s3Client = \App::make('aws')->createClient('s3', $s3_env);
        }

        //Creating a presigned URL
        $cmd = $s3Client->getCommand('GetObject', [
           'Bucket' => $Bucket,
           'Key' => $key,
           '@http' => ['sink' => $destination]
        ]);

        $result = $s3Client->execute($cmd);

        if ($result['@metadata']['statusCode'] === 200) {
            return true;
        } else {
            Log::error("Api::downloadFile - Failed to download to $destination " . $result['@metadata']['statusCode']);
            return false;
        }
    } catch (\Exception $ex) {
        Log::error("Api::downloadFile - exception: $ex->getMessage()");
        return false;
    }
}

并在主方法

downloadZip
中,替换了这些行

    $signedurl = $this->getpresignedurl($row['image']);
    @ File::copy($signedurl, $public_dir . $imagename);

    $destination = $public_dir . $imagename;
    $result = $this->downloadFile($row['image'], $destination);

此外,为了处理下载失败,添加了一个

if
条件

if (file_exists($public_dir . $imagename) {        
    array_push($zipimagesarray, array('path' => $public_dir, "image" => $imagename));
}

如果有人可以提供关于为什么在第 40 个文件之后发生自动 html 编码的解决方案,我会再等几天,然后接受此解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.