2013-10-08 42 views
4

我在需要將圖像文件上傳到Amazon S3的MEAN(MongoDB,Express,AngularJS,node.js)堆棧上構建應用程序。我按照以下方式執行:從AngularJS發佈到Amazon S3時發生錯誤

首先,將http get發送到我的API,該API指定交互的「策略文檔」並將其返回到AngularJS前端。該後端代碼看起來像這樣(與變量填寫):

exports.S3Signing = function(req, res) { 
    var bucket = "MY_BUCKET_NAME", 
     awsKey = "MY_AWS_KEY", 
     secret = "MY_SECRET", 
     fileName = req.params.userId, 
     expiration = new Date(new Date().getTime() + 1000 * 60 * 5).toISOString(); 

    var policy = { 
     "expiration": expiration, 
     "conditions": [ 
      {"bucket": bucket}, 
      {"key": fileName}, 
      {"acl": 'public-read'}, 
      ["starts-with", "$Content-Type", ""], 
      ["content-length-range", 0, 524288000] 
     ]}; 

    policyBase64 = new Buffer(JSON.stringify(policy), 'utf8').toString('base64'); 
    signature = crypto.createHmac('sha1', secret).update(policyBase64).digest('base64'); 
    res.json({bucket: bucket, awsKey: awsKey, policy: policyBase64, signature: signature}); 
}; 

這個過程的前端(AngularJS)的代碼如下所示:

$http.get('/api/v1/auth/signS3/' + userId).success(function(data, status) { 
       var formData = new FormData(); 
       formData.append('key', userId); 
       formData.append('AWSAccessKeyId', data.awsKey); 
       formData.append('acl', 'public-read'); 
       formData.append('policy', data.policy); 
       formData.append('signature', data.signature); 
       formData.append('Content-Type', image.type); 
       formData.append('file', image); 

       $http({ 
        method: 'POST', 
        url: 'http://' + data.bucket + '.s3.amazonaws.com/', 
        headers: {'Content-Type': 'multipart/form-data'}, 
        data: formData 
       }).success(function(data) { 
        deferred.resolve(data); 
       }).error(function(err) { 
        deferred.reject(err); 
       }); 
      }).error(function(err, status) { 
       deferred.reject(err); 
      }); 

然而,因爲它是目前,如果我張貼圖片,我得到以下錯誤:

Malformed POST Request The body of your POST request is not well-formed multipart/form-data. 

如果我改變HTTP POST調用AngularJS速記和刪除「內容類型」:「多/表單數據」規範,像這樣的:

$http.post('http://' + data.bucket + '.s3.amazonaws.com/', formData).success(function(data) { 
        deferred.resolve(data); 
       }).error(function(err) { 
        deferred.reject(err); 
       }); 

我碰到下面的錯誤,而不是:

Precondition Failed At least one of the pre-conditions you specified did not hold Bucket POST must be of the enclosure-type multipart/form-data 

我已經試過的,我能想到的條件和規定的任意組合。我在這裏錯過了什麼?

+0

可能相關:http://stackoverflow.com/questions/23098223 /上傳-FORMDATA-從觸發-IO-鍛造到亞馬遜-S3 –

回答

1

我相信問題出在我試圖上傳的「文件」格式。我使用的是AngularJS指令this,它返回的大小調整圖像的格式並不像實際的文件。我仍然使用相同的指令,但不再使用圖像大小調整。

我改變了上傳過程的結構來完成node.js後端的大部分工作。該AngularJS功能如下:

uploadImage: function(image, userId) { 
      var deferred = $q.defer(), 
       formData = new FormData(); 

      formData.append('image', image, image.name); 

      $http.post('/api/v1/user/' + userId + '/image', formData, { 
       transformRequest: angular.identity, 
       headers: { 'Content-Type': undefined } 
      }).success(function(data, status) { 
       deferred.resolve(data); 
      }).error(function(err, status) { 
       deferred.reject(err); 
      }); 

      return deferred.promise; 
     } 

而且Node.js的/ Express端點後看起來像這樣:

exports.uploadImage = function(req, res) { 
    postToS3 = function(image, userId) { 
     var s3bucket = new AWS.S3({params: {Bucket: config.aws.bucket}}), 
      deferred = Q.defer(), 
      getExtension = function(filename) { 
       var i = filename.lastIndexOf('.'); 
       return (i < 0) ? '' : filename.substr(i); 
      }, 
      dataToPost = { 
       Bucket: config.aws.bucket, 
       Key: 'user_imgs/' + userId + getExtension(image.name), 
       ACL: 'public-read', 
       ContentType: image.type 
      }; 

     fs.readFile(image.path, function(err, readFile) { 
      dataToPost.Body = readFile; 

      s3bucket.putObject(dataToPost, function(err, data) { 
       if (err) { 
        deferred.reject(err.message); 
       } else { 
        deferred.resolve(data); 
       } 
      }); 
     }); 

     return deferred.promise; 
    }; 

    postToS3(req.files.image, req.params.userId).then(function(data) { 
     res.json(200, data); 
    }, function(err) { 
     res.send(500, err); 
    }) 
}; 

現在這是使用亞馬遜的AWS sdk for node.js

0

最近我還面臨同樣的問題。您需要將dataURI轉換爲Blob並上傳從此函數返回的文件。它上傳的S3上傳很好。

function dataURItoBlob(dataURI) { 
    // convert base64/URLEncoded data component to raw binary data held in a string 
    var byteString; 
    if (dataURI.split(',')[0].indexOf('base64') >= 0) 
     byteString = atob(dataURI.split(',')[1]); 
    else 
     byteString = unescape(dataURI.split(',')[1]); 

    // separate out the mime component 
    var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0] 

    // write the bytes of the string to a typed array 
    var ia = new Uint8Array(byteString.length); 
    for (var i = 0; i < byteString.length; i++) { 
     ia[i] = byteString.charCodeAt(i); 
    } 

    return new Blob([ia], {type:mimeString}); 
} 
0

應該工作,如果你只刪除:

headers: {'Content-Type': 'multipart/form-data'}, 

和圖像我剛剛給類似:

$("#your_image_id").files[0] 
相關問題