前提・実現したいこと
AWSのS3へ作成したwebサイトからローカルファイルをアップロードしwebサイトにアップロードしたファイル(動画)を表示できるようにしたいのですがアップロードしようとするとエラーが発生してしまいうまくいきません。アップロードの流れは、ファイルを選択するとカスタムオーソライザーがユーザーを認証し、lamda関数がアップロードに必要な認証情報を作成しブラウザに送られ、HTTP POSTを使いS3へのアップロードが始まるといった内容です。使用しているブラウザはChromeで他にもFireFox、Edge、IEなどを試しましたがダメでした。
発生している問題・エラーメッセージ
アップロードするとこのようなエラーが発生します。
Access to XMLHttpRequest at 'https://pnr3lfkpvf.execute-api.us-east-1.amazonaws.com/dev/s3-policy-document?filename=sample.mp4' from origin 'http://mywebsite' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. jquery.min.js:4 GET https://pnr3lfkpvf.execute-api.us-east-1.amazonaws.com/dev/s3-policy-document?filename=sample.mp4 net::ERR_FAILED
一つ目のエラーメッセージはChromeのAllow CORS: Access-Control-Allow-originという拡張機能を使用すると消えるのですが、二つの目エラーメッセージは消えませんでした。
該当のソースコード
アップロードに必要な認証情報を生成するlambda関数です。
JavaScript
1'use strict'; 2 3 var AWS = require('aws-sdk'); 4 var async = require('async'); 5 var crypto = require('crypto'); 6 7 var s3 = new AWS.S3(); 8 9 function createErrorResponse(code, message) { 10 var response = { 11 'statusCode': code, 12 'headers' : {'Access-Control-Allow-Origin' : '*'}, 13 'body' : JSON.stringify({'message' : message}) 14 } 15 16 return response; 17 } 18 19 function createSuccessResponse(message) { 20 var response = { 21 'statusCode': 200, 22 'headers' : {'Access-Control-Allow-Origin' : '*'}, 23 'body' : JSON.stringify(message) 24 } 25 26 return response; 27 } 28 29 function base64encode (value) { 30 return new Buffer(value).toString('base64'); 31 } 32 33 function generateExpirationDate() { 34 var currentDate = new Date(); 35 currentDate = currentDate.setDate(currentDate.getDate() + 1); 36 return new Date(currentDate).toISOString(); 37 } 38 39 function generatePolicyDocument(filename, next) { 40 var directory = crypto.randomBytes(20).toString('hex'); 41 var key = directory + '/' + filename; 42 var expiration = generateExpirationDate(); 43 44 var policy = { 45 'expiration' : expiration, 46 'conditions': [ 47 {key: key}, 48 {bucket: process.env.UPLOAD_BUCKET}, 49 {acl: 'private'}, 50 ['starts-with', '$Content-Type', ''] 51 ] 52 }; 53 54 next(null, key, policy); 55 } 56 57 function encode(key, policy, next) { 58 var encoding = base64encode(JSON.stringify(policy)).replace('\n',''); 59 next(null, key, policy, encoding); 60 } 61 62 function sign(key, policy, encoding, next) { 63 var signature = crypto.createHmac('sha1', process.env.SECRET_ACCESS_KEY).update(encoding).digest('base64'); 64 next(null, key, policy, encoding, signature); 65 } 66 67 exports.handler = function(event, context, callback){ 68 var filename = null; 69 70 if (event.queryStringParameters && event.queryStringParameters.filename) { 71 filename = decodeURIComponent(event.queryStringParameters.filename); 72 } else { 73 callback(null, createErrorResponse(500, 'Filename must be provided')); 74 return; 75 } 76 77 async.waterfall([async.apply(generatePolicyDocument, filename), encode, sign], 78 function (err, key, policy, encoding, signature) { 79 if (err) { 80 callback(null, createErrorResponse(500, err)); 81 } else { 82 var result = 83 { 84 signature: signature, 85 encoded_policy: encoding, 86 access_key: process.env.ACCESS_KEY, 87 upload_url: process.env.UPLOAD_URI + '/' + process.env.UPLOAD_BUCKET, 88 key: key 89 } 90 91 callback(null, createSuccessResponse(result)); 92 } 93 } 94 ) 95 };
webサイトからファイルをS3にアップロードするためのlambda関数です。
javascript
1var uploadController = { 2 data: { 3 config: null 4 }, 5 uiElements: { 6 uploadButton: null 7 }, 8 init: function (configConstants) { 9 this.data.config = configConstants; 10 this.uiElements.uploadButton = $('#upload'); 11 this.uiElements.uploadButtonContainer = $('#upload-video-button'); 12 this.uiElements.uploadProgressBar = $('#upload-progress'); 13 14 this.wireEvents(); 15 }, 16 wireEvents: function () { 17 var that = this; 18 19 this.uiElements.uploadButton.on('change', function (result) { 20 var file = $('#upload').get(0).files[0]; 21 var requestDocumentUrl = that.data.config.apiBaseUrl + '/s3-policy-document?filename=' + encodeURI(file.name); 22 23 $.get(requestDocumentUrl, function (data, status) { 24 that.upload(file, data, that) 25 }); 26 }); 27 }, 28 upload: function (file, data, that) { 29 30 this.uiElements.uploadButtonContainer.hide(); 31 this.uiElements.uploadProgressBar.show(); 32 this.uiElements.uploadProgressBar.find('.progress-bar').css('width', '0'); 33 34 35 var fd = new FormData(); 36 fd.append('key', data.key) 37 fd.append('acl', 'private'); 38 fd.append('Content-Type', file.type); 39 fd.append('AWSAccessKeyId', data.access_key); 40 fd.append('policy', data.encoded_policy) 41 fd.append('signature', data.signature); 42 fd.append('file', file, file.name); 43 44 $.ajax({ 45 url: data.upload_url, 46 type: 'POST', 47 data: fd, 48 processData: false, 49 contentType: false, 50 xhr: this.progress, 51 beforeSend: function (req) { 52 req.setRequestHeader('Authorization', '*'); 53 } 54 }).done(function (response) { 55 that.uiElements.uploadButtonContainer.show(); 56 that.uiElements.uploadProgressBar.hide(); 57 alert('Uploaded Finished'); 58 }).fail(function (response) { 59 that.uiElements.uploadButtonContainer.show(); 60 that.uiElements.uploadProgressBar.hide(); 61 alert('Failed to upload'); 62 }) 63 }, 64 progress: function () { 65 var xhr = $.ajaxSettings.xhr(); 66 xhr.upload.onprogress = function (evt) { 67 var percentage = evt.loaded / evt.total * 100; 68 $('#upload-progress').find('.progress-bar').css('width', percentage + '%'); 69 }; 70 return xhr; 71 } 72}
カスタムオーソライザーです。
Javascript
1'use strict'; 2 3var jwt = require('jsonwebtoken'); 4 5var generatePolicy = function(principalId, effect, resource) { 6 var authResponse = {}; 7 authResponse.principalId = principalId; 8 if (effect && resource) { 9 var policyDocument = {}; 10 policyDocument.Version = '2012-10-17'; 11 policyDocument.Statement = []; 12 var statementOne = {}; 13 statementOne.Action = 'execute-api:Invoke'; 14 statementOne.Effect = effect; 15 statementOne.Resource = resource; 16 policyDocument.Statement[0] = statementOne; 17 authResponse.policyDocument = policyDocument; 18 } 19 return authResponse; 20} 21 22exports.handler = function(event, context, callback){ 23 if (!event.authorizationToken) { 24 callback('Could not find authToken'); 25 return; 26 } 27 28 var token = event.authorizationToken.split(' ')[1]; 29 30 var secretBuffer = new Buffer(process.env.AUTH0_SECRET); 31 jwt.verify(token, secretBuffer, function(err, decoded){ 32 if(err){ 33 console.log('Failed jwt verification: ', err, 'auth: ', event.authorizationToken); 34 callback('Authorization Failed'); 35 } else { 36 callback(null, generatePolicy('user', 'allow', event.methodArn)); 37 } 38 }) 39};
試したこと
CORSに関するエラーはChromeの拡張機能を使ったり、セキュリティを外して実行したりすると消えるのですが、もう一つのエラーが消えませんでした。
補足情報(FW/ツールのバージョンなど)
エラーの原因がはっきりとわからないので、どこを見直すべきか分かりませんでした。情報がございましたらご指摘お願いいたします。
あなたの回答
tips
プレビュー