Setting XMLHttpRequest.responseType forbidden all of a sudden?

前端 未结 4 1769
谎友^
谎友^ 2020-12-03 21:05

I\'ve been using synchronous XMLHttpRequest with responseType set to \"arraybuffer\" for quite a while to load a binary file and wait until it is loaded. Today, I got this e

相关标签:
4条回答
  • 2020-12-03 21:24

    Workaround

    For the casual reader, if you still need the synchronous behavior, you can download your content as string and then convert it to byte data

    NOTA:
    This workaround assumes the original request.response is an ASCII text.
    If this assumption doesn't fit your specific use case please see jBinary.

    I convert it to an ArrayBuffer.

    var request = new XMLHttpRequest();
    request.open('GET', url, false);
    request.send(null);
    
    var data;
    if (request.status === 200) {
        data = stringToArrayBuffer(request.response);
    } else {
        alert('Something bad happen!\n(' + request.status + ') ' + request.statusText);
    }
    
    // ...
    
    function stringToArrayBuffer(str) {
        var buf = new ArrayBuffer(str.length);
        var bufView = new Uint8Array(buf);
    
        for (var i=0, strLen=str.length; i<strLen; i++) {
            bufView[i] = str.charCodeAt(i);
        }
    
        return buf;
    }
    

    More reading

    • jBinary: High-level API for working with binary data in Javascript.
    • Sending and Receiving Binary Data: Binary data handling with vanilla Javascript. (Source: Mozilla Developer Network)

    References

    • Converting between strings and ArrayBuffers
    • Renato Mangini's original function str2ab
    • Easier ArrayBuffer <-> String conversion with the Encoding API (Jeff Posnik)
    0 讨论(0)
  • 2020-12-03 21:30

    This is correct behaviour, as defined in the Specification of XMLHttpRequest:

    When set: throws an "InvalidAccessError" exception if the synchronous flag is set and there is an associated XMLHttpRequest document.

    The responseType property cannot be set when the XMLHttpRequest is not async, that is, synchronous. Setting the third parameter of open to false causes the request to be synchronous.

    0 讨论(0)
  • 2020-12-03 21:34

    As it's not possible to set responseType = 'arraybuffer' in sync mode, receiving string and converting to bytes is a solution, but as Stephan said, your data should be an ascii text. You will receive wrong value (253) instead of all bytes above 127.

    But setting mime-type and charset to x-user-defined might be a solution:

    Here server send 10 bytes from 125 to 134:

    request = new XMLHttpRequest();
    request.overrideMimeType('text/plain; charset=x-user-defined');
    request.open('GET', url, false);
    request.send();
    Uint8Array.from(request.response, c => c.charCodeAt(0));
    > Uint8Array(10) [125, 126, 127, 128, 129, 130, 131, 132, 133, 134]
    

    without setting mime-type it's like this:

    request = new XMLHttpRequest();
    request.open('GET', url, false);
    request.send();
    Uint8Array.from(request.response, c => c.charCodeAt(0));
    > Uint8Array(10) [125, 126, 127, 253, 253, 253, 253, 253, 253, 253]
    
    0 讨论(0)
  • 2020-12-03 21:45

    If you're lucky enough to have control over the entry point of the whole page, consider wrapping the whole thing with an async function and using await to block on problematic asynchronous code. Might not work with all use cases though.

    (async function () {
        await problem_function_1();
        await problem_function_2();
        ... normal page logic pasted here ...
    })(); 
    

    Wrap async code that is not a promise with a Promise (so that await works as expected), and call the resolve function manually in whatever constitutes a "success callback". Do the same for reject if possible.

    0 讨论(0)
提交回复
热议问题