2015-05-21 3 views
6

Fatal error: Uncaught Aws\S3\Exception\InvalidRequestException: AWS Error Code: InvalidRequest, Status Code: 400, AWS Request ID: B1A28EBE65521DF4, AWS Error Type: client, AWS Error Message: You must specify at least one part, User-Agent: aws-sdk-php2/2.7.22 Guzzle/3.9.2 curl/7.40.0 PHP/5.6.6 thrown in C:\vhosts********.com\db*****\FileUploader_v2\aws\Aws\Common\Exception\NamespaceExceptionFactory.php on line 91Aws S3 CompleteMultipartUpload error

Я получаю вышеуказанную ошибку всякий раз, когда запускаю программу многопользовательской загрузки, используя AWS S3. Моя программа должна разрезать часть файла в скрипте JS, который затем отправляется на php-скрипт с использованием XMLHTTPRequest. Эта часть, похоже, работает хорошо. Однако проблема возникает, когда вызывается CompleteMultipartUpload. Из ошибки я понимаю, что моя часть слишком мала или пуста.

upload.htm:

var command; var file; var ownerName; var totalSize; var partSize = 2 * 1024 * 1024; // constant var sendBackData; var totalSize; var sureUploadSize = 0, probableUplaodSize = 0; var numParts; var partsLeft = [];

function _(el){ 
     return document.getElementById(el); 
    } 

    function calcTotalSize(file){ 
     var size_total = 0; 
     for(var i = 0; i < file.length; i++){ 
      size_total += file[i].size; 
     } 
     return size_total; 
    } 

    function uploadFile(){ 
     file = _("file").files[0]; 
     console.log(file); 
     ownerName = _("name").value; 
     totalSize = file.size; 
     command = 'CreateMultipartUpload'; 

     var formdata = new FormData(); 
     formdata.append("command", command); 
     formdata.append("filename", file.name); 
     formdata.append("name", ownerName); 
     var ajax = new XMLHttpRequest(); 
     ajax.open("POST", "FileUploader.php", true); 
     ajax.send(formdata); 
     ajax.onreadystatechange = function() { 
      if (ajax.readyState === 4) { 
       sendBackData = JSON.parse(ajax.responseText); 
       numParts = Math.ceil(totalSize/partSize); 
       uploadPart(1); 
      } 
     }; 
    } 

    function uploadPart(partNum){ 
     console.log("Uploading part " + partNum); 
     console.log(sendBackData['uploadId']); 
     command = 'UploadPart'; 

     if (partNum > numParts) { 
      completeMultipartUpload(); 
      return; 
     } 

     var formdata = new FormData(); 

     var start = (partNum - 1) * partSize; 
     var end = start + partSize; 
     if (end > totalSize) 
      end = totalSize; 
     var length = end - start; 
     var curBlobPart = file.slice(start, end); 

     //console.log(sendBackData['uploadId']); 

     formdata.append("file[]", curBlobPart); 
     formdata.append("command", command); 
     formdata.append("uploadId", sendBackData['uploadId']); 
     formdata.append("key", sendBackData['key']); 
     formdata.append("partNumber", partNum); 

     var ajax = new XMLHttpRequest(); 
     ajax.open("POST", "FileUploader.php", true); 
     ajax.addEventListener("load", completeHandler, false); 
     ajax.addEventListener("error", errorHandler, false); 
     ajax.addEventListener("abort", abortHandler, false); 
     ajax.send(formdata); 
     ajax.onreadystatechange = function() { 
      if (ajax.readyState === 4) { 
       uploadPart(partNum + 1); 
      } 
     }; 
    } 

    function completeMultipartUpload() { 
     command = 'CompleteMultipartUpload'; 

     var formdata = new FormData(); 
     formdata.append("command", command); 
     formdata.append("uploadId", sendBackData['uploadId']); 
     formdata.append("key", sendBackData['key']); 

     var ajax = new XMLHttpRequest(); 
     ajax.open("POST", "FileUploader.php", true); 
     ajax.addEventListener("load", completeHandler, false); 
     ajax.addEventListener("error", errorHandler, false); 
     ajax.addEventListener("abort", abortHandler, false); 
     ajax.send(formdata); 
     ajax.onreadystatechange = function() { 
      if (ajax.readyState === 4) { 
       alert("File uploaded successfully"); 
      } 
     }; 
    } 

    function progressHandler(event){ 
     _("loaded_n_total").innerHTML = "Uploaded "+event.loaded+" bytes of "+event.total; 
     var percent = (event.loaded/event.total) * 100; 
     _("progressBar").value = Math.round(percent); 
     _("status").innerHTML = Math.round(percent)+"% uploaded... please wait"; 
    } 
    function completeHandler(event){ 
     _("status").innerHTML = event.target.responseText; 
     _("progressBar").value = 0; 
    } 
    function errorHandler(event){ 
     _("status").innerHTML = "Upload Failed"; 
    } 
    function abortHandler(event){ 
     _("status").innerHTML = "Upload Aborted"; 
    }` 

FileUploader.php: `

//require 'SimpleImage.php'; 
//require 'gifsplit.php'; 
//require 'functions.php'; 

require 'config.php'; 
require 'aws/aws-autoloader.php'; 

use Aws\Common\Exception\MultipartUploadException; 
use Aws\S3\Model\MultipartUpload\UploadBuilder; 
use Aws\S3\S3Client; 
use Aws\S3\Exception\S3Exception; 

function sendJson($arr) 
{ 
    header('Content-Type: application/json'); 
    die(json_encode($arr)); 
} 

// S3 
$s3 = S3Client::factory(array(
    'key' => AWS_KEY, 
    'secret' => AWS_SECRET_KEY 
)); 

//$part = $_POST['part']; 

switch ($_POST['command']) { 
    case 'CreateMultipartUpload': 
     $key = "other/".$_POST['name']."/".$_POST['filename']; 

     $response = $s3->createMultipartUpload(array(
      'Bucket' => TMP_IMG, 
      'Key'  => $key 
     )); 

     $uploadId = $response['UploadId']; 

     sendJson(array(
      'uploadId' => $uploadId, 
      'key'  => $key 
     )); 
     break; 

    case 'UploadPart': 
     var_dump($_FILES['file']); 

     $result = $s3->uploadPart(array(
      'Bucket' => TMP_IMG, 
      'Key'  => $_POST['key'], 
      'UploadId' => $_POST['uploadId'], 
      'PartNumber'=> $_POST['partNumber'], 
      'Body'  => $_FILES['file']['tmp_name'] 
     )); 
     break; 

    case 'CompleteMultipartUpload': 
     $partsModel = $s3->listParts(array(
      'Bucket' => TMP_IMG, 
      'Key'  => $_POST['key'], 
      'UploadId' => $_POST['uploadId'] 
     )); 

     $model = $s3->completeMultipartUpload(array(
      'Bucket' => TMP_IMG, 
      'Key' => $_POST['key'], 
      'UploadId' => $_POST['uploadId'], 
      'Parts' => $partsModel['Parts'] 
     )); 

     sendJson(array(
      'success' => true 
     )); 
     break; 

    case 'AbortMultipartUpload': 
     # code... 
     break; 

    default: 
     # code... 
     break; 
} 

Есть что-нибудь, что, очевидно, неправильно о том, как я выполнении моего задача. Моя единственная мысль заключалась в том, что моя часть размером слишком мала для загрузки. Если это так, у меня есть работа для этого с другой версией моего проекта, над которой я работал.

ответ

11

Я просто потрачу несколько минут * на эту же проблему, пока не понял, что аргумент Parts должен быть вложен в запись MultipartUpload. Мой код теперь выглядит так:

$completeParams = Array(
    'Bucket' => $multipartUpload['Bucket'], 
    'Key' => $multipartUpload['Key'], 
    'MultipartUpload' => Array(
     'Parts' => $parts, 
    ), 
    'UploadId' => $multipartUpload['UploadId'] 
); 

$res = $client->completeMultipartUpload($completeParams); 

И это работает отлично. По крайней мере, при использовании версии 3 SDK. Версия 2 SDK ожидает частей непосредственно в $ params.

* Не укажу, сколько минут

+1

Это было действительно полезно - ни одна из документации или примеров не упоминает об этом! – benJ

+0

безупречное спасибо –