AngularJS - 将图像上载到SharePoint库/损坏的文件

时间:2015-05-27 18:32:42

标签: angularjs rest sharepoint

我使用以下Angular模块尝试通过Web浏览器将图像上传到SharePoint:https://github.com/nervgh/angular-file-upload

我获得了200条POST消息并且正在上传文件...但是,它并未在预览或打开图像时显示图像本身,而是显示[X]。我猜这与内容的编码方式有关,但不确定下一步该怎么做。这是我的控制器:

appControllers.controller('appUploadImageCtrl', ['$scope', '$location', 'FileUploader', function ($scope, $location, FileUploader) {
    var uploader = $scope.uploader = new FileUploader({
        url: "/sites/_api/web/lists/getByTitle('Images')/RootFolder/Files/add(url='test.jpg',overwrite='true')",
        processData: false,
        transformRequest: angular.identity,
        headers: {
            'Accept': 'application/json;odata=verbose', 'content-type': undefined, 'X-RequestDigest': $("#__REQUESTDIGEST").val() }
    });

    // FILTERS

    uploader.filters.push({
        name: 'imageFilter',
        fn: function (item /*{File|FileLikeObject}*/, options) {
            var type = '|' + item.type.slice(item.type.lastIndexOf('/') + 1) + '|';
            return '|jpg|png|jpeg|bmp|gif|'.indexOf(type) !== -1;
        }
    });

    // CALLBACKS

    uploader.onWhenAddingFileFailed = function (item /*{File|FileLikeObject}*/, filter,

    options) {
        console.info('onWhenAddingFileFailed', item, filter, options);
    };
    uploader.onAfterAddingFile = function (fileItem) {
        console.info('onAfterAddingFile', fileItem);
    };
    uploader.onAfterAddingAll = function (addedFileItems) {
        console.info('onAfterAddingAll', addedFileItems);
    };
    uploader.onBeforeUploadItem = function (item) {
        console.info('onBeforeUploadItem', item);
    };
    uploader.onProgressItem = function (fileItem, progress) {
        console.info('onProgressItem', fileItem, progress);
    };
    uploader.onProgressAll = function (progress) {
        console.info('onProgressAll', progress);
    };
    uploader.onSuccessItem = function (fileItem, response, status, headers) {
        console.info('onSuccessItem', fileItem, response, status, headers);
    };
    uploader.onErrorItem = function (fileItem, response, status, headers) {
        console.info('onErrorItem', fileItem, response, status, headers);
    };
    uploader.onCancelItem = function (fileItem, response, status, headers) {
        console.info('onCancelItem', fileItem, response, status, headers);
    };
    uploader.onCompleteItem = function (fileItem, response, status, headers) {
        console.info('onCompleteItem', fileItem, response, status, headers);
    };
    uploader.onCompleteAll = function () {
        console.info('onCompleteAll');
    };

    console.info('uploader', uploader);

    $scope.cancel = function () {
        $location.path('/');
    }
}]);

HTML:

        <div class="col-md-3">
            <h3>Select files</h3>
            <div ng-show="uploader.isHTML5">
                <!-- 3. nv-file-over uploader="link" over-class="className" -->
                <div class="well my-drop-zone" nv-file-over="" uploader="uploader">
                    Base drop zone
                </div>
                <!-- Example: nv-file-drop="" uploader="{Object}" options="{Object}" filters="{String}" -->
                <div nv-file-drop="" uploader="uploader" options="{ url: '/foo' }">
                    <div nv-file-over="" uploader="uploader" over-class="another-file-over-class" class="well my-drop-zone">
                        Another drop zone with its own settings
                    </div>
                </div>
            </div>
            <!-- Example: nv-file-select="" uploader="{Object}" options="{Object}" filters="{String}" -->
            Multiple
            <input type="file" nv-file-select="" uploader="uploader" multiple /><br />
            Single
            <input type="file" nv-file-select="" uploader="uploader" />
        </div>
        <div class="col-md-9" style="margin-bottom: 40px">
            <h3>Upload queue</h3>
            <p>Queue length: {{ uploader.queue.length }}</p>
            <table class="table">
                <thead>
                    <tr>
                        <th width="50%">Name</th>
                        <th ng-show="uploader.isHTML5">Size</th>
                        <th ng-show="uploader.isHTML5">Progress</th>
                        <th>Status</th>
                        <th>Actions</th>
                    </tr>
                </thead>
                <tbody>
                    <tr ng-repeat="item in uploader.queue">
                        <td><strong>{{ item.file.name }}</strong></td>
                        <td ng-show="uploader.isHTML5" nowrap>{{ item.file.size/1024/1024|number:2 }} MB</td>
                        <td ng-show="uploader.isHTML5">
                            <div class="progress" style="margin-bottom: 0;">
                                <div class="progress-bar" role="progressbar" ng-style="{ 'width': item.progress + '%' }"></div>
                            </div>
                        </td>
                        <td class="text-center">
                            <span ng-show="item.isSuccess"><i class="glyphicon glyphicon-ok"></i></span>
                            <span ng-show="item.isCancel"><i class="glyphicon glyphicon-ban-circle"></i></span>
                            <span ng-show="item.isError"><i class="glyphicon glyphicon-remove"></i></span>
                        </td>
                        <td nowrap>
                            <button type="button" class="btn btn-success btn-xs" ng-click="item.upload()" ng-disabled="item.isReady || item.isUploading || item.isSuccess">
                                <span class="glyphicon glyphicon-upload"></span> Upload
                            </button>
                            <button type="button" class="btn btn-warning btn-xs" ng-click="item.cancel()" ng-disabled="!item.isUploading">
                                <span class="glyphicon glyphicon-ban-circle"></span> Cancel
                            </button>
                            <button type="button" class="btn btn-danger btn-xs" ng-click="item.remove()">
                                <span class="glyphicon glyphicon-trash"></span> Remove
                            </button>
                        </td>
                    </tr>
                </tbody>
            </table>
            <div>
                <div>
                    Queue progress:
                    <div class="progress" style="">
                        <div class="progress-bar" role="progressbar" ng-style="{ 'width': uploader.progress + '%' }"></div>
                    </div>
                </div>
                <button type="button" class="btn btn-success btn-s" ng-click="uploader.uploadAll()" ng-disabled="!uploader.getNotUploadedItems().length">
                    <span class="glyphicon glyphicon-upload"></span> Upload all
                </button>
                <button type="button" class="btn btn-warning btn-s" ng-click="uploader.cancelAll()" ng-disabled="!uploader.isUploading">
                    <span class="glyphicon glyphicon-ban-circle"></span> Cancel all
                </button>
                <button type="button" class="btn btn-danger btn-s" ng-click="uploader.clearQueue()" ng-disabled="!uploader.queue.length">
                    <span class="glyphicon glyphicon-trash"></span> Remove all
                </button>
            </div>
        </div>

1 个答案:

答案 0 :(得分:2)

您的代码存在的问题是,您尝试将图像上传为正常byte array,但是当您通过SharePoint REST API上传到库时,这是不可能的。

为了能够将非文本文件上传到SharePoint,必须将它们作为base64编码的字节数组上传。

您的选择是使用另一个Angular模块,例如Angular-Base64-Upload,或者在使用您选择的第一个文件上传模块上传图像文件之前对其进行编码。

如果您选择第二个选项,您可以使用以下技术对图像进行编码,不过它如何与您选择的文件上传器一起使用,我不能说。您似乎可以修改文件上传器中file的{​​{1}}属性,因此不应该那么难。

将图像文件编码为base64二进制数组缓冲区

FileItem

当我为项目编写类似的代码时,我注意到SharePoint(或IE)在获取MIME类型时遇到了问题。我最终从图像中剥离它以使其工作,如下所示。

//Create a new FileReader object
var reader = new FileReader();
reader.onload = processImage;

//Read the file as a base64 encoded string
reader.readAsDataURL(input.files[0]);

function processImage () {
    //The image file has been read by the filereader
    //and can be converted to an arraybuffer
    var arrayBuffer = base64ToBinary(this.result);

    //Upload the image to the SharePoint images library
    uploadImage(arrayBuffer);
}

function base64ToBinary (base64EncodedFile) {
    var BASE64_MARKER = ';base64,';
    var base64Index = base64EncodedFile.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
    var base64 = base64EncodedFile.substring(base64Index);
    var raw = atob(base64);
    var rawLength = raw.length;
    var array = new Uint8Array(rawLength);

    for (i = 0; i < rawLength; i++)
    {
        array[i] = raw.charCodeAt(i);
    }
    return array.buffer;
}

使用REST API和Ajax

上传到SharePoint图像库

如果您决定不使用Angular模块上传文件,则可以使用带有jquery的常规ajax调用通过REST API将文件直接上传到SharePoint库。这可能必须针对Angular语法进行修改,但概念是相同的。

var raw = atob(base64.replace(/^data:image\/(png|jpg);base64,/, ""));