Dropbox Chooser returns corrupted file

2019-09-11 15:55发布

问题:

posting here because I've not received a response over at the dropbox forums. dropbox forum post

A few months ago I implemented the dropbox chooser and got everything working fine. Then about a week ago I ran into an issue where .pdf files would open, but contain blank pages and .docx files won't open at all (.rtf and .txt files open just fine)

Anyway I started digging and it turns out that the xhr.responseText that comes back is short a number of bytes (approximately 4% short in pdf files)

I've taken a look at the bytes and the beginning and end of file are correct (different versions have the same issue):

%PDF-1.5
...
%%EOF

Here's the relevant code:

var options = {
    success: function(files) 
    {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", files[0].link, false);
        xhr.responseType = 'arrayBuffer';
        xhr.onreadystatechange = function(oEvent)
        {
            if (xhr.readyState === 4 && xhr.status === 200)
            {
                    var buffer = xhr.responseText;
                    console.log('File size: ' + files[0].bytes + 
                                ' | Buffer size: ' + buffer.length +
                                ' | Header size: ' + xhr.getResponseHeader('Content-Length'));
            }
        }
        xhr.setRequestHeader("User-Agent", navigator.userAgent);
        try 
        {
            xhr.send(null);
        } 
        catch (err) 
        {
            alert(err);
        }
    },
    linkType: "direct", // or "preview"
    multiselect: false, // or true
};

Dropbox.choose(options);

In the console the "File size" and "Header size" values are the same, but the "Buffer size", the responseText, it smaller...

Why is dropbox returning all of the file contents?

回答1:

I think the issue is that you're reading from the XMLHttpRequest's responseText field instead of response. My guess would be that this results in (incorrectly) trying to interpret the data as text characters.

EDIT: You also need to change arrayBuffer to arraybuffer to actually get an ArrayBuffer back. Then you need to check the byteLength field to get the actual number of bytes contained in the ArrayBuffer.

Note that to use the arraybuffer response type, you'll need to switch to using an asynchronous XMLHttpRequest. (Drop the false last parameter to xhr.open or change its value to true.)

EDIT2:

A working (for me) example is at https://downloadtest.site44.com. The code is as follows:

Dropbox.choose({
    success: function (files) {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', files[0].link);
        xhr.responseType = 'arraybuffer';
        xhr.onreadystatechange = function (oEvent) {
            if (xhr.readyState === 4 && xhr.status === 200) {
                var buffer = xhr.response;
                console.log('File size: ' + files[0].bytes + 
                    ' | Buffer size: ' + buffer.byteLength + 
                    ' | Header size: ' + xhr.getResponseHeader('Content-Length'));
            }
        };
        xhr.send();
    },

    linkType: 'direct'
});