javascript - AngularJS GET byte[] error when downloading binary data using ASP.NET Web API - Stack Overflow

For additional background information on this issue, see UploadingDownloading Byte Arrays with Angular

For additional background information on this issue, see Uploading/Downloading Byte Arrays with AngularJS and ASP.NET Web API.

While working on a TypeScript/AngularJS(v1.2.22)/Web API solution for uploading/download byte arrays, I discovered a scenario where AngularJS does not respond correctly to a client-side GET request for byte array data. To prove out my server code, I created some separate XMLHttpRequest code outside of Angular that does work properly with the Web API server code.

  1. There may be something that I am still missing in the AngularJS code, but I have scoured numerous documents, articles and code examples and have not found anything that is obviously wrong with the code.
  2. I have verified that the data sent from the server through Fiddler is identical for the AngularJS and XMLHttpRequest code.
  3. The first issue with the Angular code is that it interprets the data as a string, NOT a byte array, while the XMLHttpRequest code interprets that code correctly as a byte array.
  4. The second issue is that the AngularJS code corrupts all values greater than 127 (i.e., 128-255). I included a screen shot of this below.
  5. The third issue is that data is lost. The reconstructed data in the AngularJS code had only 217 bytes instead of 256 bytes.

Here is the XMLHttpRequest code that works. Note that the response is a valid argument for the UInt8Array constructor.

    var oReq = new XMLHttpRequest();
    oReq.open("GET", "/api/Values", true);
    // Worked on IE, Chrome, and Firefox with this line mented out, Firefox docs say it should be declared.
    oReq.overrideMimeType("charset=x-user-defined");
    oReq.responseType = "arraybuffer";
    oReq.onload = function () {
        var arrayBuffer = oReq.response, bArray = new Uint8Array(arrayBuffer), str = "";
        if (arrayBuffer) {
            for (var i = 0; i < bArray.length; i++) {
                str += bArray[i] + ((i < bArray.length - 1) ? "," : "");
            }
            window.alert("XMLHttpRequest GET Output: " + str);
        }
    };

Here is the AngularJS code that does not work correctly (i.e., return a byte[] with the correct values). Note that the response had to be converted from a string to an array.

    $http({
        method: 'GET',
        url: 'api/values',
        headers: {'Content-Type': 'application/octet-stream; charset=x-user-defined'},
        // The issue was caused by using camel case B. MUST BE 'arraybuffer'
        // Changed code below to reflect correction.
        responseType: 'arraybuffer',
        transformResponse: []
    }).success(function (response, status) {
            if (status === 200) {// Issue 1: response is not byte[]. It is a string. Issue 2: String values > 127 are corrupted.
                var buffer = new ArrayBuffer(response.length), bArray = new Uint8Array(buffer), len = bArray.length, i, str = "";
                for (i = 0; i < len; i++) {// Cannot create an array from response data here, but I can using XMLHttpRequest.
                    str += bArray[i] = response[i].charCodeAt(0);// Have to read character value.
                    if (i < len - 1)
                        str += ",";
                }
                window.alert("Angular Output: " + str);
                var unsigned8Int = new Uint8Array(bArray);// Can create new array here after processing string values.
                var b64Encoded = btoa(String.fromCharCode.apply(null, unsigned8Int));
                callback(b64Encoded);
            }
        }).error((data, status) => {
            console.log('[ERROR] Status Code:' + status);
        });

I annotated the issues in the AngularJS code above. I tried many variations to the above code based upon various articles, but none worked. I tried the default transformResponse, but found one article that said the defaults had to be reset.

The server-side code is as follow:

    [AcceptVerbs("Get")]
    public HttpResponseMessage Get()
    {
        byte[] item = new byte[256];
        for (var i = 0; i < item.Length; i++)
        {
            item[i] = (byte)i;
        }
        HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
        result.Content = new ByteArrayContent(item);
        result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        return result;
    }

I checked the hex data in Fiddler for each test case below, and it was identical (i.e., 000102...EFFF), and the length in Fiddler was 256. Inside the Angular code, the data length was only 217 versus 256, so data is being corrupted and lost.

Below are two screen shots of the two different GET code blocks above.

I repeated the tests with an image injected in the server code instead of the 256 byte array. Again, the image data content (see below) and length (27,998 bytes) was identical in Fiddler.

The received image inside the Angular code block had to be converted from a string to a byte array, and the size was much smaller (~20K).

There seems to be two possibilities: 1) My AngularJS code is bad, or 2) There is a problem with Angular.

I will attempt to dive into the AngularJS code in the debugger, but I am not sure how far I will get.

I could really use help with this from some of you Angular jocks.

Thanks...

Update Eric Eslinger just pointed out my error. arrayBuffer MUST BE arraybuffer (no camel)

For additional background information on this issue, see Uploading/Downloading Byte Arrays with AngularJS and ASP.NET Web API.

While working on a TypeScript/AngularJS(v1.2.22)/Web API solution for uploading/download byte arrays, I discovered a scenario where AngularJS does not respond correctly to a client-side GET request for byte array data. To prove out my server code, I created some separate XMLHttpRequest code outside of Angular that does work properly with the Web API server code.

  1. There may be something that I am still missing in the AngularJS code, but I have scoured numerous documents, articles and code examples and have not found anything that is obviously wrong with the code.
  2. I have verified that the data sent from the server through Fiddler is identical for the AngularJS and XMLHttpRequest code.
  3. The first issue with the Angular code is that it interprets the data as a string, NOT a byte array, while the XMLHttpRequest code interprets that code correctly as a byte array.
  4. The second issue is that the AngularJS code corrupts all values greater than 127 (i.e., 128-255). I included a screen shot of this below.
  5. The third issue is that data is lost. The reconstructed data in the AngularJS code had only 217 bytes instead of 256 bytes.

Here is the XMLHttpRequest code that works. Note that the response is a valid argument for the UInt8Array constructor.

    var oReq = new XMLHttpRequest();
    oReq.open("GET", "/api/Values", true);
    // Worked on IE, Chrome, and Firefox with this line mented out, Firefox docs say it should be declared.
    oReq.overrideMimeType("charset=x-user-defined");
    oReq.responseType = "arraybuffer";
    oReq.onload = function () {
        var arrayBuffer = oReq.response, bArray = new Uint8Array(arrayBuffer), str = "";
        if (arrayBuffer) {
            for (var i = 0; i < bArray.length; i++) {
                str += bArray[i] + ((i < bArray.length - 1) ? "," : "");
            }
            window.alert("XMLHttpRequest GET Output: " + str);
        }
    };

Here is the AngularJS code that does not work correctly (i.e., return a byte[] with the correct values). Note that the response had to be converted from a string to an array.

    $http({
        method: 'GET',
        url: 'api/values',
        headers: {'Content-Type': 'application/octet-stream; charset=x-user-defined'},
        // The issue was caused by using camel case B. MUST BE 'arraybuffer'
        // Changed code below to reflect correction.
        responseType: 'arraybuffer',
        transformResponse: []
    }).success(function (response, status) {
            if (status === 200) {// Issue 1: response is not byte[]. It is a string. Issue 2: String values > 127 are corrupted.
                var buffer = new ArrayBuffer(response.length), bArray = new Uint8Array(buffer), len = bArray.length, i, str = "";
                for (i = 0; i < len; i++) {// Cannot create an array from response data here, but I can using XMLHttpRequest.
                    str += bArray[i] = response[i].charCodeAt(0);// Have to read character value.
                    if (i < len - 1)
                        str += ",";
                }
                window.alert("Angular Output: " + str);
                var unsigned8Int = new Uint8Array(bArray);// Can create new array here after processing string values.
                var b64Encoded = btoa(String.fromCharCode.apply(null, unsigned8Int));
                callback(b64Encoded);
            }
        }).error((data, status) => {
            console.log('[ERROR] Status Code:' + status);
        });

I annotated the issues in the AngularJS code above. I tried many variations to the above code based upon various articles, but none worked. I tried the default transformResponse, but found one article that said the defaults had to be reset.

The server-side code is as follow:

    [AcceptVerbs("Get")]
    public HttpResponseMessage Get()
    {
        byte[] item = new byte[256];
        for (var i = 0; i < item.Length; i++)
        {
            item[i] = (byte)i;
        }
        HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
        result.Content = new ByteArrayContent(item);
        result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        return result;
    }

I checked the hex data in Fiddler for each test case below, and it was identical (i.e., 000102...EFFF), and the length in Fiddler was 256. Inside the Angular code, the data length was only 217 versus 256, so data is being corrupted and lost.

Below are two screen shots of the two different GET code blocks above.

I repeated the tests with an image injected in the server code instead of the 256 byte array. Again, the image data content (see below) and length (27,998 bytes) was identical in Fiddler.

The received image inside the Angular code block had to be converted from a string to a byte array, and the size was much smaller (~20K).

There seems to be two possibilities: 1) My AngularJS code is bad, or 2) There is a problem with Angular.

I will attempt to dive into the AngularJS code in the debugger, but I am not sure how far I will get.

I could really use help with this from some of you Angular jocks.

Thanks...

Update Eric Eslinger just pointed out my error. arrayBuffer MUST BE arraybuffer (no camel)

Share Improve this question edited May 23, 2017 at 12:26 CommunityBot 11 silver badge asked Sep 26, 2014 at 12:46 HighdownHighdown 6241 gold badge11 silver badges24 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 5

The specific call to make is

$http.get('http://example.', {responseType: 'arraybuffer'})

and you'll get a proper binary response.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744993472a4605045.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信