使用ASP.NET Web API下载二进制数据时,AngularJS GET byte []错误

时间:2014-09-26 12:47:00

标签: javascript arrays angularjs binary-data

有关此问题的其他背景信息,请参阅Uploading/Downloading Byte Arrays with AngularJS and ASP.NET Web API

在处理用于上传/下载字节数组的TypeScript / AngularJS(v1.2.22)/ Web API解决方案时,我发现了AngularJS无法正确响应字节数组数据的客户端GET请求的情况。为了证明我的服务器代码,我在Angular之外创建了一些单独的XMLHttpRequest代码,它可以正常使用Web API服务器代码。

  1. 在AngularJS代码中可能还有一些我仍然缺少的东西,但是我已经搜索了大量的文档,文章和代码示例,并且没有找到任何明显错误的代码。
  2. 我已经验证通过Fiddler从服务器发送的数据对于AngularJS和XMLHttpRequest代码是相同的。
  3. Angular代码的第一个问题是它将数据解释为字符串,而不是字节数组,而XMLHttpRequest代码将该代码正确解释为字节数组。
  4. 第二个问题是AngularJS代码破坏了大于127的所有值(即128-255)。我在下面添加了一个屏幕截图。
  5. 第三个问题是数据丢失了。 AngularJS代码中的重建数据只有217个字节而不是256个字节。
  6. 这是有效的XMLHttpRequest代码。请注意,响应是UInt8Array构造函数的有效参数。

        var oReq = new XMLHttpRequest();
        oReq.open("GET", "/api/Values", true);
        // Worked on IE, Chrome, and Firefox with this line commented 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);
            }
        };
    

    以下是无法正常工作的AngularJS代码(即,返回具有正确值的byte [])。请注意,响应必须从字符串转换为数组。

        $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);
            });
    

    我在上面的AngularJS代码中注释了这些问题。我根据各种文章尝试了上述代码的许多变体,但都没有奏效。我尝试了默认的transformResponse,但发现一篇文章说默认值必须重置。

    服务器端代码如下:

        [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;
        }
    

    我在下面的每个测试用例中检查了Fiddler中的十六进制数据,它是相同的(即000102 ... EFFF),并且Fiddler中的长度是256.在Angular代码中,数据长度仅为217 256,因此数据被破坏和丢失。

    以下是上面两个不同GET代码块的两个屏幕截图。

    Screen Shots

    我用服务器代码中注入的图像而不是256字节数组重复测试。同样,Fiddler中的图像数据内容(见下文)和长度(27,998字节)相同。

    GET Image Response

    Angular代码块内的接收图像必须从字符串转换为字节数组,并且尺寸要小得多(~20K)。

    似乎有两种可能性:1)我的AngularJS代码不好,或者2)Angular存在问题。

    我将尝试深入研究调试器中的AngularJS代码,但我不确定我会得到多远。

    我真的可以从你们的一些角色运动员那里得到帮助。

    ...谢谢

    更新Eric Eslinger刚刚指出我的错误。 arrayBuffer必须是arraybuffer(没有驼峰)

1 个答案:

答案 0 :(得分:5)

具体的make调用是

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

你会得到一个合适的二元回应。