6

I've got this jquery/REST process that I thought was uploading a PDF file to SPO 2013 Document library, but it's only producing an empty or corrupt. Anybody know why?

function ProcessUpload(fileInput) {
    var reader = new FileReader();
    reader.onload = function (result) {
        var fileName = '',
         libraryName = '',
         fileData = '';

        var byteArray = new Uint8Array(result.target.result)
        for (var i = 0; i < byteArray.byteLength; i++) {
            fileData += String.fromCharCode(byteArray[i])
        }

        // once we have the file perform the actual upload
        PerformUpload(fileInput.name, fileData);

    };
    reader.readAsArrayBuffer(fileInput);
}

function PerformUpload(fileName, fileData) {
    var url;

    //var path = appWebUrl; var p = path.split('/');var approot = p[0]+"//"+p[2]+"/"+p[3]+"/"+p[4];


        url = 'https://mytenant.sharepoint.com/sites/dev' +
        "/_api/web/lists/getByTitle(@TargetLibrary)/RootFolder/Files/add(url=@TargetFileName,overwrite='false')?"+
          "@TargetSite='" + 'https://mytenant.sharepoint.com/sites/dev'+ "'" +
            "&@TargetLibrary='Documents'" +
            "&@TargetFileName='CV" + fileName + "'";
            alert(url);


    // use the request executor (cross domain library) to perform the upload

$.ajax({     
        url: url,
        type: "POST",
        headers: {
            "Accept": "application/json; odata=verbose",
            "X-RequestDigest": $("#__REQUESTDIGEST").val()

        },
        data: JSON.stringify({ '__metadata': { 'type': 'SP.List' }, 'Title': 'New title' }),


        contentType: "application/json;odata=verbose",
        binaryStringRequestBody: true,
        body: fileData,
        success:successHandler,
        error: errorHandler
    });
}
3

What I have working is the following:

Method

 POST

URL

http://www.somewhere.com/testsite/_api/web/GetFolderByServerRelativeUrl('/testsite/Shared Documents')/Files/add(url='filename.png',overwrite=true)

Header

Content-Type: application/octet-stream
Accept: application/json;odata=verbose
X-RequestDigest: ...

Body

Raw binary bytes (no JSON)

Then in the JSON response, load the URI from the result

d.ListItemAllFields.__deferred.uri

to get the Item ID and perform regular metadata updates to set title (and content type if needed)

I haven't used the 'binaryStringRequestBody' parameter method, but if you read the section "Working with Files and Folders" here, http://msdn.microsoft.com/en-us/magazine/dn198245.aspx, you will see the method you are using is limited in how large the files can be, where as the POST with a RAW binary is not limited. That might also simply be your problem that your test file is too large for that method.

1

Data corrupted ? the problem is on fileInput:

function ProcessUpload(fileInput)
reader.readAsArrayBuffer(fileInput);

Some point to reflect:

But how can you get the fileinput ? if get fileList(files) give error or corrupt, why this parameter is file, only "FILE".

And other, i have used RequestExecutor to upload files and not AJAX with JQUERY.

But anyway, here's a suggestion, not is good practice but a solution:

Page App:

    <input type="file" id="files" />
    <input type="button" id="btnupload" onclick="ProcessUpload()" value="Upload" />

Script App:

'use strict';

var AppUrl = decodeURIComponent(getQueryStringParameter("SPAppWebUrl"));
var hostUrl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));

function uploadFile(fileName, fileData) {
    // create the deferred object
    var def = new $.Deferred();

    var fileCollectionEndpoint = String.format("{0}/_api/sp.appcontextsite(@target)/web/lists/getByTitle('{1}')/rootfolder/files/add(overwrite=false, url='{2}')?@target='{3}'", AppUrl, "Documents", fileName, hostUrl);
    var scriptbase = hostUrl + "/_layouts/15/";
    $.getScript(scriptbase + "SP.RequestExecutor.js", function() {
        var executor = new SP.RequestExecutor(AppUrl);
        // Send the request.
        executor.executeAsync({
            url: fileCollectionEndpoint,
            method: "POST",
            body: fileData,
            binaryStringRequestBody: true,
            headers: {
                "accept": "application/json;odata=verbose"
            },
            success: function(data) {
                def.resolve("File Uploaded!");
            },
            error: function(err) {
                var errJson = $.parseJSON(err.body);
                def.reject(errJson.error.message.value);
            }
        });
    });
    return def.promise();
}

function ProcessUpload() {
    var fileslist = $("#files")[0].files;
    if (fileslist.length > 0) {
        var FileInput = fileslist[0];
        var fileData = '';
        var reader = new FileReader();
        reader.onload = function(result) {
            var byteArray = new Uint8Array(result.target.result)
            for (var i = 0; i < byteArray.byteLength; i++) {
                fileData += String.fromCharCode(byteArray[i])
            }
            // once we have the file perform the actual upload
            var callUpload = uploadFile(FileInput.name, fileData);
            callUpload.done(function(result) {
                alert(result);
            });
            callUpload.fail(function(result) {
                alert(result);
            });

        };
        reader.readAsArrayBuffer(FileInput);
    }
}

function getQueryStringParameter(urlParameterKey) {
    var params = document.URL.split('?')[1].split('&');
    for (var i = 0; i < params.length; i = i + 1) {
        var singleParam = params[i].split('=');
        if (singleParam[0] == urlParameterKey) return decodeURIComponent(singleParam[1]);
    }
}

Search Links:

RequestExecutor

Upload File JS

1

b1c10's answer is probably on the right track, stating that the problem might be on the file input, try to check if you actually upload the correct stream to the REST API. If the stream is already corrupted before the actual upload, it has nothing to do with your POST. Try to convert your stream back to the original file locally and see what that tells you.

If you (or anyone else, as this question is somewhat older) are by any chance using the ng-file-upload library by danialfarid to select your files, that might be the source of your problem.

I was also getting corrupted files after the upload, and found that the library was adding an extra header and footer to the binary stream. So before you upload you would have to strip off some bytes at the beginning and end of your stream.

This guy 'Capt. Rochefort' wrote a blogpost with more details and some code to help you strip off the culprit bytes that corrupt your stream. For me, stripping of the header and footer fixed the problem, as my stream was already faulted before the actual POST.

Hope it helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.