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

Getting Policy Signing failed error and Received an empty or invalid response from the server! with Fine Uploader Serverless Upload

在尝试将文件上传到 s3 存储桶时,我不断收到 "Policy Signing failed error"、"Received an empty or invalid response from the server!" 和 "POST request for 0 has failed - response code 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

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

感谢您的反馈。你是对的。我试图在请求返回临时凭据之前设置凭据。我最终将 sts.assumeRoleWithWebIdentity 函数放入承诺中,并在解决承诺后将 运行 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));
  });