获取策略签名失败错误并从服务器收到空或无效响应!使用Fine Uploader无服务器上传

时间:2016-02-15 03:27:35

标签: angularjs facebook amazon-s3 fine-uploader

在尝试将文件上传到s3存储桶时,我不断收到“策略签名失败错误”,“从服务器收到空的或无效的响应!”,以及“0的POST请求失败 - 响应代码404”。我已经按照教程并通过Facebook应用程序配置了应用程序,并将Facebook设置为AWS IAM角色中的ID提供程序。

我可以将文件放入框中,但是错误表达的是:从服务器收到空的或无效的响应!

这是我的代码:

artwork.js

'use strict';

/**
 * @ngdoc function
 * @name artvoicesApp.controller:MainCtrl
 * @description
 * # MainCtrl
 * Controller of the artvoicesApp
 */
angular.module('artvoicesApp')
  .controller('ArtworkCtrl', ['$scope', '$firebaseObject', 'FIREBASE_URL', 'Auth', '$state', function ($scope, $firebaseObject, FIREBASE_URL, Auth, $state) {

    var artist = FIREBASE_URL.child('data/artists/');
    var artistObject = $firebaseObject(artist);
    var authData = Auth.$getAuth();
    var token = authData.facebook.accessToken;
    $scope.newArt = {};

    artistObject.$loaded().then(function() {
      $scope.artist = artistObject;
    });

    var artwork = FIREBASE_URL.child('data/artists/artwork');
    var artworkObject = $firebaseObject(artwork);

    artworkObject.$loaded().then(function() {
      $scope.artwork = artworkObject;
    });

    $scope.submitNewArt = function() {
      artwork.push({name: $scope.newArt.name, status: $scope.newArt.status, height: $scope.newArt.height, width: $scope.newArt.width, value: $scope.newArt.value});
    };

    $scope.editData = function(data, k, c) { //k is for key, c is for category
      artworkObject[k][c] = data;
      artworkObject.$save().then(function() {}, function(e) {
        console.log(e);
      });
    };

    $scope.logout = function() {
      Auth.$unauth();
      $state.go('login');
    };

    var s3Globals = {
      userName: authData.facebook.displayName,
      roleArn: 'arn:aws:iam::875128865884:role/facebook-idp-role',
      token: authData.facebook.accessToken
    };


    $(function() {
      var assumeRoleWithWebIdentity = function(params) {
              var sts = new AWS.STS(),
                  assumeRoleParams = {};
              // s3Globals.roleArn = s3Globals.roleArn;
              // s3Globals.providerId = s3Globals.providerId;
               //params.idToken || s3Globals.idToken;

              assumeRoleParams = {
                  ProviderId: 'graph.facebook.com',
                  RoleArn: s3Globals.roleArn,
                  RoleSessionName: "web-identity-federation",
                  WebIdentityToken: s3Globals.token
              };

              // if (s3Globals.providerId) {
              //     assumeRoleParams.ProviderId = s3Globals.providerId;
              // }

              sts.assumeRoleWithWebIdentity(assumeRoleParams, params.callback || s3Globals.updateCredentials);
          },
          getFuCredentials = function(data) {
              return {
                  accessKey: data.Credentials.AccessKeyId,
                  secretKey: data.Credentials.SecretAccessKey,
                  sessionToken: data.Credentials.SessionToken,
                  expiration: data.Credentials.Expiration
              };
          };

      s3Globals.assumeRoleWithWebIdentity = assumeRoleWithWebIdentity;
      s3Globals.getFuCredentials = getFuCredentials;
    });

    $(function() {
        var bucketUrl = "https://artvoicestest.s3.amazonaws.com",
            updateCredentials = function(error, data) {
                if (!error) {
                    $('#uploader').fineUploaderS3("setCredentials", s3Globals.getFuCredentials(data));
                }
            };

        $("#uploader").fineUploaderS3({
            request: {
                endpoint: bucketUrl
            },
            objectProperties: {
                // Since we want all items to be publicly accessible w/out a server to return a signed URL
                acl: "public-read",

                //The key for each file will follow this format: {USER_NAME}/{UUID}.{FILE_EXTENSION}
                key: function(id) {
                    var filename = this.getName(id),
                        uuid = this.getUuid(id);

                    return qq.format("{}/{}.{}", s3Globals.userName, uuid, qq.getExtension(filename));
                }
            },
            chunking: {
                enabled: true
            },
            resume: {
                enabled: true
            },
            // Restrict files to 15 MB and 5 net files per session
            validation: {
                itemLimit: 5,
                sizeLimit: 15000000
            },
            thumbnails: {
                placeholders: {
                    notAvailablePath: "not_available-generic.png",
                    waitingPath: "waiting-generic.png"
                }
            }
        })
            .on('complete', function(event, id, name, response, xhr) {
                var $fileEl = $(this).fineUploaderS3("getItemByFileId", id),
                    $viewBtn = $fileEl.find(".view-btn"),
                    key = $(this).fineUploaderS3("getKey", id);

                // Add a "view" button to access the uploaded file in S3 if the upload is successful
                if (response.success) {
                    $viewBtn.show();
                    $viewBtn.attr("href", bucketUrl + "/" + key);
                }
            })
            .on("credentialsExpired", function() {
                var promise = new qq.Promise();

                // Grab new credentials
                s3Globals.assumeRoleWithWebIdentity({
                    callback: function(error, data) {
                        if (error) {
                            promise.failure("Failed to assume role");
                        }
                        else {
                            promise.success(s3Globals.getFuCredentials(data));
                        }
                    }
                });

                return promise;
            });

        s3Globals.updateCredentials = updateCredentials;
        // $(document).on("tokenReceived.s3", function() {
        //     $("#uploader").show();
        // });
        // $(document).trigger("tokenExpired.s3");
    });

  }]);

的index.html

    <script type="text/template" id="qq-template">
        <div class="qq-uploader-selector qq-uploader" qq-drop-area-text="Drop files here">
            <div class="qq-total-progress-bar-container-selector qq-total-progress-bar-container">
                <div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-total-progress-bar-selector qq-progress-bar qq-total-progress-bar"></div>
            </div>
            <div class="qq-upload-drop-area-selector qq-upload-drop-area" qq-hide-dropzone>
                <span class="qq-upload-drop-area-text-selector"></span>
            </div>
            <div class="qq-upload-button-selector qq-upload-button">
                <div>Upload a file</div>
            </div>
                <span class="qq-drop-processing-selector qq-drop-processing">
                    <span>Processing dropped files...</span>
                    <span class="qq-drop-processing-spinner-selector qq-drop-processing-spinner"></span>
                </span>
            <ul class="qq-upload-list-selector qq-upload-list" aria-live="polite" aria-relevant="additions removals">
                <li>
                    <div class="qq-progress-bar-container-selector">
                        <div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-progress-bar-selector qq-progress-bar"></div>
                    </div>
                    <span class="qq-upload-spinner-selector qq-upload-spinner"></span>
                    <span class="qq-upload-file-selector qq-upload-file"></span>
                    <span class="qq-edit-filename-icon-selector qq-edit-filename-icon" aria-label="Edit filename"></span>
                    <input class="qq-edit-filename-selector qq-edit-filename" tabindex="0" type="text">
                    <span class="qq-upload-size-selector qq-upload-size"></span>
                    <button type="button" class="qq-btn qq-upload-cancel-selector qq-upload-cancel">Cancel</button>
                    <button type="button" class="qq-btn qq-upload-retry-selector qq-upload-retry">Retry</button>
                    <button type="button" class="qq-btn qq-upload-delete-selector qq-upload-delete">Delete</button>
                    <span role="status" class="qq-upload-status-text-selector qq-upload-status-text"></span>
                </li>
            </ul>

            <dialog class="qq-alert-dialog-selector">
                <div class="qq-dialog-message-selector"></div>
                <div class="qq-dialog-buttons">
                    <button type="button" class="qq-cancel-button-selector">Close</button>
                </div>
            </dialog>

            <dialog class="qq-confirm-dialog-selector">
                <div class="qq-dialog-message-selector"></div>
                <div class="qq-dialog-buttons">
                    <button type="button" class="qq-cancel-button-selector">No</button>
                    <button type="button" class="qq-ok-button-selector">Yes</button>
                </div>
            </dialog>

            <dialog class="qq-prompt-dialog-selector">
                <div class="qq-dialog-message-selector"></div>
                <input type="text">
                <div class="qq-dialog-buttons">
                    <button type="button" class="qq-cancel-button-selector">Cancel</button>
                    <button type="button" class="qq-ok-button-selector">Ok</button>
                </div>
            </dialog>
        </div>
    </script>

    <script>var s3DemoGlobals = {};</script>


    <!-- endbuild -->
    <script type="text/javascript">
      !function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","page","once","off","on"];analytics.factory=function(t){return function(){var e=Array.prototype.slice.call(arguments);e.unshift(t);analytics.push(e);return analytics}};for(var t=0;t<analytics.methods.length;t++){var e=analytics.methods[t];analytics[e]=analytics.factory(e)}analytics.load=function(t){var e=document.createElement("script");e.type="text/javascript";e.async=!0;e.src=("https:"===document.location.protocol?"https://":"http://")+"cdn.segment.com/analytics.js/v1/"+t+"/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(e,n)};analytics.SNIPPET_VERSION="3.1.0";
      analytics.load("0A4Y3sUzm9iPLwDEcwyLoxaDvicWeiws");
      analytics.page()
      }}();
    </script>
  </head>
  <body ng-app="artvoicesApp">
    <!--[if lte IE 8]>
      <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
    <![endif]-->

    <!-- Add your site or application content here -->
    <!-- <div class="header">
      <div class="navbar navbar-default" role="navigation">
        <div class="container">
          <div class="navbar-header">

            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#js-navbar-collapse">
              <span class="sr-only">Toggle navigation</span>
              <span class="icon-bar"></span>
              <span class="icon-bar"></span>
              <span class="icon-bar"></span>
            </button>

            <a class="navbar-brand" style="text-align: center" href="#/">ArtVoices</a>
          </div>

          <div class="collapse navbar-collapse" id="js-navbar-collapse">

            <ul class="nav navbar-nav">
            </ul>
          </div>
        </div>
      </div>
    </div> -->

    <!-- The element where Fine Uploader will exist. -->


    <ui-view></ui-view>


    <!-- Google Analytics: change UA-XXXXX-X to be your site's ID -->
     <script>
       !function(A,n,g,u,l,a,r){A.GoogleAnalyticsObject=l,A[l]=A[l]||function(){
       (A[l].q=A[l].q||[]).push(arguments)},A[l].l=+new Date,a=n.createElement(g),
       r=n.getElementsByTagName(g)[0],a.src=u,r.parentNode.insertBefore(a,r)
       }(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

       ga('create', 'UA-XXXXX-X');
       ga('send', 'pageview');
    </script>

    <!-- build:js(.) scripts/vendor.js -->
    <!-- bower:js -->
    <script src="bower_components/jquery/dist/jquery.js"></script>
    <script src="bower_components/angular/angular.js"></script>
    <script src="bower_components/bootstrap/dist/js/bootstrap.js"></script>
    <script src="bower_components/angular-xeditable/dist/js/xeditable.js"></script>
    <script src="bower_components/angular-animate/angular-animate.js"></script>
    <script src="bower_components/angular-cookies/angular-cookies.js"></script>
    <script src="bower_components/angular-resource/angular-resource.js"></script>
    <script src="bower_components/angular-route/angular-route.js"></script>
    <script src="bower_components/angular-sanitize/angular-sanitize.js"></script>
    <script src="bower_components/angular-touch/angular-touch.js"></script>
    <script src="bower_components/angular-ui-router/release/angular-ui-router.js"></script>
    <script src="bower_components/firebase/firebase.js"></script>
    <script src="bower_components/angularfire/dist/angularfire.js"></script>
    <script src="bower_components/lodash/lodash.js"></script>
    <script src="bower_components/cloudinary-core/cloudinary-core.js"></script>
    <script src="bower_components/cloudinary_ng/js/angular.cloudinary.js"></script>
    <script src="bower_components/animateCSS/dist/jquery.animatecss.js"></script>
    <script src="https://sdk.amazonaws.com/js/aws-sdk-2.2.35.min.js"></script>
    <script src="fine-uploader/s3.jquery.fine-uploader.min.js"></script>



    <!-- endbowe->
    <!-- endbuild -->

        <!-- build:js({.tmp,app}) scripts/scripts.js -->
        <script src="scripts/app.js"></script>
        <script src="scripts/controllers/artwork.js"></script>
        <script src="scripts/controllers/auth.js"></script>
        <script src="scripts/factories/authfactory.js"></script>
        <script src="scripts/factories/login.js"></script>
        <!-- endbuild -->
</body>
</html>

artwork.html

上传者位于div id =“uploader”

<div id="artwork-page" ng-cloak>
  <div class="row">
    <div class="col-md-2 col-md-offset-1 col-sm-4 col-sm-offset-1 col-xs-4 col-xs-offset-1">
      <p><button class="btn btn-default" ng-click="logout()"><i class="fa fa-sign-out"></i> Logout</button></p>
    </div>
  </div>
  <div class="row text-center">
    <h1 class="artist-name">{{artist.name}}</h1>
  </div>
  <div id="add-art-div">
    <a style="color: white" class="btn btn-success btn-lg" data-target="#add-art" data-toggle="modal"><i class="fa fa-plus"></i> Add Art</a>
  </div>
  <div id="stripe-div">

  </div>
  <div class="add-art-modal">
    <!-- Modal -->
    <div class="modal fade" id="add-art" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
      <div class="modal-dialog" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
            <h4 class="modal-title" id="myModalLabel" style="text-align: center">Add Artwork</h4>
          </div>
          <div class="modal-body">
            <div class="row drag-drop-add">
              <div class="col-12 text-center">
                <div id="uploader"></div>
                <p>Drop Image <i class="fa fa-arrow-up"></i></p>
              </div>
              <div class="col-sm-6 col-md-4 col-md-offset-1 text-center">
                <img src="images/audio_file.png" class="drag-image">
                <div id="fine-uploader"></div>

                <p>Drop Audio <i class="fa fa-arrow-up"></i></p>
              </div>
            </div>
            <form name="addArt" ng-submit="submitNewArt()" novalidate>
              <div class="form-group row">
                <label for="exampleInputName2" class="col-sm-1 form-control-label">Name:</label>
                <div class="col-sm-10 modal-input">
                  <input type="text" class="form-control" id="exampleInputName2" ng-required="true" ng-model="newArt.name">
                </div>
              </div>
              <div class="form-group row">
                <label for="exampleInputValue" class="col-sm-1 form-control-label">Value:</label>
                <div class="col-sm-10 modal-input">
                  <input type="text" class="form-control" id="exampleInputValue" ng-required="true" ng-model="newArt.value">
                </div>
              </div>
              <div class="form-group row">
                <label for="exampleInputStatus" class="col-sm-1 form-control-label">Status:</label>
                <div class="col-sm-10 modal-input">
                  <input type="text" class="form-control" id="exampleInputStatus" ng-required="true" ng-model="newArt.status">
                </div>
              </div>
              <div class="form-group row">
                <label for="exampleInputHeight" class="col-sm-1 form-control-label">Height:</label>
                <div class="col-sm-10 modal-input">
                  <input type="text" class="form-control" id="exampleInputHeight" ng-required="true" ng-model="newArt.height">
                </div>
              </div>
              <div class="form-group row">
                <label for="exampleInputWidth" class="col-sm-1 form-control-label">Width:</label>
                <div class="col-sm-10 modal-input">
                  <input type="text" class="form-control" id="exampleInputWidth" ng-required="true" ng-model="newArt.width">
                </div>
              </div>
              <p class="warning" ng-show="addArt.$invalid">*All Items must be filled in to Add Item</p>
              <div class="add-art">
                <button type="submit" class="btn btn-primary add-art" ng-disabled="addArt.$invalid">Submit Artwork</button>
              </div>
            </form>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="row">
    <div class="card-columns">
      <div class="col-md-4 col-sm-6 col-xs-12 text-center" ng-repeat="(key, v) in artwork">
        <div class="card animated" ng-mouseenter="hover = true" ng-mouseleave="hover = false" ng-class="{pulse: hover}">
          <h4 class="card-title art-name">{{v.descriptionText}}</h4>
          <img class="card-img-top artwork" src="{{v.imageUrl}}" alt="Card image cap">
          <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
            <ul class="list-group list-group-flush">
                <li class="list-group-item"><strong>Status:</strong> <button class="btn btn-normal" onbeforesave="editData($data, key, 'status')" editable-text="v.status">{{ v.status || "empty" }} <i class="fa fa-pencil-square-o"></i></button></li>
                <li class="list-group-item"><strong>Price:</strong> <button class="btn btn-normal" onbeforesave="editData($data, key, 'value')" editable-text="v.value">${{ v.value || "empty" }} <i class="fa fa-pencil-square-o"></i></button></li>
                <li class="list-group-item"><strong>Width:</strong> <button class="btn btn-normal" onbeforesave="editData($data, key, 'width')" editable-text="v.width">{{ v.width || "empty" }} <i class="fa fa-pencil-square-o"></i></button></li>
                <li class="list-group-item"><strong>Height:</strong> <button class="btn btn-normal" onbeforesave="editData($data, key, 'height')" editable-text="v.height">{{ v.height || "empty" }} <i class="fa fa-pencil-square-o"></i></button></li>
            </ul>
        </div>
      </div>
    </div>
  </div>
</div>

调试日志

    s3.jquery.fine-uploader.min.js:16 [Fine Uploader 5.5.0] Parsing template
    s3.jquery.fine-uploader.min.js:16 [Fine Uploader 5.5.0] Template parsing complete
    s3.jquery.fine-uploader.min.js:16 [Fine Uploader 5.5.0] Rendering template in DOM.
    s3.jquery.fine-uploader.min.js:16 [Fine Uploader 5.5.0] Template rendering complete
    http://localhost:9000/%7B%7Bv.imageUrl%7D%7D Failed to load resource: the server responded with a status of 404 (Not Found)
    s3.jquery.fine-uploader.min.js:16 [Fine Uploader 5.5.0] Received 1 files.
    s3.jquery.fine-uploader.min.js:16 [Fine Uploader 5.5.0] Attempting to validate image.
    s3.jquery.fine-uploader.min.js:16 [Fine Uploader 5.5.0] Sending simple upload request for 0
    s3.jquery.fine-uploader.min.js:16 [Fine Uploader 5.5.0] Submitting S3 signature request for 0
    s3.jquery.fine-uploader.min.js:16 [Fine Uploader 5.5.0] Sending POST request for 0
    http://localhost:9000/null Failed to load resource: the server responded with a status of 404 (Not Found)
    s3.jquery.fine-uploader.min.js:16 [Fine Uploader 5.5.0] POST request for 0 has failed - response code 404qq.log @ s3.jquery.fine-uploader.min.js:16
    s3.jquery.fine-uploader.min.js:16 [Fine Uploader 5.5.0] Error attempting to parse signature response: SyntaxError: Unexpected token Cqq.log @ s3.jquery.fine-uploader.min.js:16
    s3.jquery.fine-uploader.min.js:16 [Fine Uploader 5.5.0] Received an empty or invalid response from the server!qq.log @ s3.jquery.fine-uploader.min.js:16
    s3.jquery.fine-uploader.min.js:16 [Fine Uploader 5.5.0] Policy signing failed.  Received an empty or invalid response from the server!qq.log @ s3.jquery.fine-uploader.min.js:16
    s3.jquery.fine-uploader.min.js:16 [Fine Uploader 5.5.0] Simple upload request failed for 0

2 个答案:

答案 0 :(得分:0)

Fine Uploader S3尝试发送签名请求的事实表明,在上传第一个文件之前,您没有通过选项或API提供任何类型的凭据。您需要设置一些断点并找出您的代码未提供临时凭证的原因。

答案 1 :(得分:0)

感谢您的反馈。你是对的。我试图在使用临时凭证返回请求之前设置凭据。我最终将sts.assumeRoleWithWebIdentity函数放入一个promise并在解析promise后运行fineUploaderS3方法。这是代码:

<强> s3Factory.js

angular.module('artvoicesApp')
  .factory('s3Factory', ['$q', function ($q) {

    var s3Object = {};

    s3Object.getTempCredentials = function(s3Globals) {
      var defer = $q.defer();
      var assumeRoleParams = {
          RoleArn: s3Globals.roleArn,
          RoleSessionName: "web-identity-federation",
          WebIdentityToken: s3Globals.token
      };
      if (s3Globals.providerId) {
        assumeRoleParams.ProviderId = s3Globals.providerId;
      }
      var sts = new AWS.STS();
      sts.assumeRoleWithWebIdentity(assumeRoleParams, function (err, data) {
        if (err) { console.log(err, err.stack); } // an error occurred
        else    { defer.resolve(data);}         // successful response
      });

      return defer.promise;
    };

    s3Object.assignCredentials = function(data) {
          return {
              accessKey: data.Credentials.AccessKeyId,
              secretKey: data.Credentials.SecretAccessKey,
              sessionToken: data.Credentials.SessionToken,
              expiration: data.Credentials.Expiration
          };
    };

    return s3Object;

  }]);

<强> artwork.js

  s3Factory.getTempCredentials(s3Globals).then(function(data) {
    $("#uploader").fineUploaderS3("setCredentials", s3Factory.assignCredentials(data));
  });