Uploading BLOB/ArrayBuffer with Dropzone.js

2019-04-10 08:23发布

问题:

Using SharePoint 2013 REST API, I'm successfully uploading files, such as .docx or .png's to a folder inside a document library using Dropzone.js. I have a function where I initialize my dropzone as follows:

myDropzone = new Dropzone("#dropzone");

myDropzone.on("complete", function (file) {
    myDropzone.removeFile(file);
});

myDropzone.options.autoProcessQueue = false;

myDropzone.on("addedfile", function (file) {
    $('.dz-message').hide();
    myDropzone.options.url = String.format(
    "{0}/{1}/_api/web/getfolderbyserverrelativeurl('{2}')/files" +
    "/add(overwrite=true, url='{3}')",
    _spPageContextInfo.siteAbsoluteUrl, _spPageContextInfo.webServerRelativeUrl, folder.d.ServerRelativeUrl, file.name);
});

myDropzone.options.previewTemplate = $('#preview-template').html();

myDropzone.on('sending', function (file, xhr, fd) {
    xhr.setRequestHeader('X-RequestDigest', $('#__REQUESTDIGEST').val());
});

The problem I've encountered is that almost all the files (PDF being the only one not) are shown as corrupt files when the upload is done. This is most likely due to the fact SharePoint requires that the file being uploaded is sent as an ArrayBuffer. MSDN Source

Using a regular Ajax POST and the method above to convert the file to an arraybuffer, I've successfully uploaded content to the SharePoint document library, without them getting corrupt. Now, I would like to do the same but without having to omit the use of Dropzone.js, that adds a very nice touch to the interface of the functionality.

I've looked into modifying the uploadFiles()-method in dropzone.js, but that seems drastic. I've also tried to figure out whether or not I can use the accept option in options but that seems like a dead end.

The two most similar problems with solutions are the ones linked below, where the first seems to be applicable in my case, but at the same time looks less "clean" than I would want to use.

The second one is for uploading images with a Base64 encoding.

1 - Simulating XHR to get ArrayBuffer

2 - Upload image as Base64 with Dropzone.js

So my question in a few less words is, when a file is added, how do I intercept this, convert the data to an arraybuffer, and then POST it using Dropzone.js?

回答1:

This is a late answer to my own question, but it is the solution we went for in the end.

We kept dropzone.js just for the nice interface and some help functions, but we decided to do the actual file upload using $.ajax().

We read the file as an array buffer using the HTML5 FileReader

var reader = new FileReader();
reader.onloadend = function(e) {
    resolve(e.target.result);
};
reader.onerror = function(e) {
    reject(e.target.error);
};
reader.readAsArrayBuffer(file);

and then pass it as the data argument in the ajax options.



回答2:

I recently came across this exact issue and so did some investigation into the Dropzone library.

I managed to correct the upload process for SharePoint/Office 365 by monkey patching the Dropzone.prototype.submitRequest() method to modify it to use use my own getArrayBuffer method that returns an ArrayBuffer using the FileReader API before sending it via the Dropzone generated XMLHttpRequest.

This enables me to continue to use the features of Dropzone API.

Only tested on a single auto upload, so will need further investigation for multi file upload.

Monkey patch

Dropzone.prototype.submitRequest = function (xhr, formData, files) {
    getArrayBuffer(files[0]).then(function (buffer) {
        return xhr.send(buffer);
    });
};

getArrayBuffer

function getArrayBuffer(file) {
    return new Promise(function (resolve, reject) {
        var reader = new FileReader();

        reader.onloadend = function (e) {
            resolve(e.target.result);
        };
        reader.onerror = function (e) {
            reject(e.target.error);
        };
        reader.readAsArrayBuffer(file);
    });
}

After the file is uploaded into SharePoint, I use the Dropzone 'success' event to update the file with metadata.