2015-07-23 1 views
3

У меня возникли проблемы с загрузкой файла на Amazon S3. Я разработал сервис Grails RESTful, который использует AWS Java SDK для генерации предварительно подписанных URL-адресов. Когда клиент загружает файл, он сначала извлекает предварительно подписанный URL-адрес, а затем использует его для загрузки файла непосредственно в мой ведро S3. Так что у меня есть сервис Grails, который создает заранее подписанный URL, как так ...Не удается загрузить файлы на Amazon S3 с помощью Angularjs с предварительно подписанным URL

def generateFileUploadUrl(AmazonS3Client client, String bucketName, String key, int expiryMins) { 
    GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(bucketName, key); 
    req.setMethod(HttpMethod.POST); 
    req.setExpiration(getExpiration(expiryMins)); 
    return client.generatePresignedUrl(req); 
} 

И тогда клиент извлекает URL в следующем формате ...

https://{bucketname}.amazonaws.com/{key}?AWSAccessKeyId={accesskey}&Expires={expiry}&Signature={signature} 

Затем клиент создает запрос POST с помощью Даниал Фарид Angular File Upload module как так ...

Upload.upload({ 
    url: destUrl, // url shown above 
    file: file 
}).progress(function (evt) { 
    var progressPercentage = parseInt(100.0 * evt.loaded/evt.total); 
    console.log('progress: ' + progressPercentage + '% ' + evt.config.file.name); 
}).success(function (data, status, headers, config) { 
    console.log('file ' + config.file.name + 'uploaded. Response: ' + data); 
}).error(function (data, status, headers, config) { 
    console.log('error status: ' + status); 
}); 

Сначала я получил ошибки о настройках CORS, но после редактирования конфигурации происхождения CORS в разрешениях моего ведра, я нормативы rted получая 403 запрещенный ответ вместо. Сообщение в ответе 403: «Подписанная нами подпись запроса не соответствует предоставленной вами подписке. Проверьте свой ключ и метод подписи. '. Ключ доступа AWS и подпись были сопоставлены, поэтому я не уверен, что такое точная ошибка.

Есть ли у моей просьбы дополнительную информацию? Посмотрел на несколько других сообщений, например this, который вручную создает документ политики для отправки с URL-адресом, но не использует AWS Java SDK.

Как это бывает, мой подход отлично работает с запросами GET, и я могу получить документы. Просто не могу загрузить.

+0

'req.setMethod (HttpMethod.POST),' '... но Post' =' PUT'!. .. –

+0

Извините, моя вина. Я должен был сказать POST. Поправил пост, спасибо. – CSharp

ответ

1

Я знаю, что это старый вопрос, но он по-прежнему кажется актуальным и по-прежнему кажется довольно сложным, чтобы получить эту работу. S3 подписанная загрузка URL-адресов довольно специфична в отношении полей, используемых в запросе, и ответ, и сообщения об ошибках не слишком полезны, как вы видите - я предполагаю, что это намерение по соображениям безопасности, но это затрудняет отладку.

Также были внесены изменения в процесс подписки AWS - версия в это время (март 2016 года) является подписью AWS версии 4 (http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html). Вы должны быть осторожны, глядя на примеры и Stackoverflow и т. Д., Что информация относится к той же версии сигнатуры, которую вы используете, так как они плохо смешиваются.

Я начал использовать AWS SDK для загрузки файла с угловым/узловым файлом, но в итоге ему было легче создавать политику на стороне сервера (node.js) без SDK. Здесь есть хороший пример (хотя и узел, а не Grails): https://github.com/danialfarid/ng-file-upload/wiki/Direct-S3-upload-and-Node-signing-example (но обратите внимание на проблему с именем ведра S3 здесь: AngularJs Image upload to S3).

Одним из ключевых моментов в том, что вы правильно указываете тип содержимого файла в генерации политики и что этот тип содержимого правильно соответствует типу содержимого файла, который вы фактически загружаете.

Для справки это код на угловой стороне, которая работает для меня:

$scope.upload = function (file) { 
    console.log("WebUploadCtrl upload"); 
    console.log("WebUploadCtrl sending S3sign request"); 
    var query = { 
     filename: file.name, 
     type: file.type 
    }; 
    $http.post('/api/s3sign', query).success(function(response) { 
     console.log("WebUploadCtrl s3sign response received"); 
     var s3ResponseParams = response; 
     console.log("WebUploadCtrl upload AWSAccessKeyId: " + response.AWSAccessKeyId); 
     console.log("WebUploadCtrl upload signature: " + response.Signature); 
     $scope.upload = Upload.upload({ 
       url: s3ResponseParams.url, //s3Url 
       transformRequest: function(data, headersGetter) { 
        var headers = headersGetter(); 
        delete headers.Authorization; 
        return data; 
       }, 
       fields: s3ResponseParams.fields, //credentials 
       method: 'POST', 
       file: file 
      }).progress(function(evt) { 
       $scope.progressPerCent = parseInt(100.0 * evt.loaded/evt.total); 
       console.log('progress: ' + $scope.progressPerCent); 
      }).success(function(data, status, headers, config) { 
       // file is uploaded successfully 
       console.log('file ' + config.file.name + 'is uploaded successfully. Response: ' + data);     

      }).error(function() { 
       // Some error has occured 
       console.log('Error uploading to S3'); 
      }); 
    }); 
}; 
+0

Спасибо за ваш ответ Мик, очень информативный. – CSharp

Смежные вопросы