使用 jQuery AJAX 下载二进制文件

IT技术 javascript jquery ajax
2021-02-21 09:36:50

我正在尝试使用 jQuery AJAX 下载二进制音频文件。

通常我只会发出这样的命令:

 windows.location.href = 'http://marksdomain(dot)com/audioFile.wav' ;

但是,最近我们的服务器等待响应的时间太长了,我收到了令人讨厌的网关超时消息。

有人建议我改用 jQuery AJAX,从那时起我就可以更好地控制超时。

这是我迄今为止玩过的代码:

$.ajax({
    url: 'http://marksdomain(dot)com/audioFile.wav',
    timeout: 999999,
    dataType: 'binary',
    processData: false, // this one does not seem to do anything ?

    success: function (result) {
        console.log(result.length);
    },
    error: function (result, errStatus, errorMessage) {
        console.log(errStatus + ' -- ' + errorMessage);
    }
};

当我省略“dataType”时,二进制文件的大小大约是服务器上实际大小的三倍。但是,当我使 dataType 等于“binary”时,AJAX 会抛出错误:

"No conversion from text to binary"

从一些较早的帖子中,听起来好像 jQuery AJAX 无法以这种方式处理二进制文件。

我确实发现Delivery.js对于我正在尝试的内容实际上非常有效,但如果可能的话,我宁愿不使用节点解决方案。

有什么建议?

3个回答

直接使用XHR就可以了。这个例子取自MDN

var oReq = new XMLHttpRequest();
oReq.open("GET", "/myfile.png", true);
oReq.responseType = "arraybuffer";

oReq.onload = function(oEvent) {
  var arrayBuffer = oReq.response;

  // if you want to access the bytes:
  var byteArray = new Uint8Array(arrayBuffer);
  // ...

  // If you want to use the image in your DOM:
  var blob = new Blob([arrayBuffer], {type: "image/png"});
  var url = URL.createObjectURL(blob);
  someImageElement.src = url;

  // whatever...
};

oReq.send();
真的 - 我添加了“oReq.timeout = 9999999;” - 虽然现在我想知道这是否一直是一些 apache 问题。
2021-04-26 09:36:50
问题是这个解决方案仍然会遇到超时问题,就像使用“windows.location.href”一样。
2021-05-02 09:36:50
但是现在您可以访问请求对象并且可以timeout在发送请求之前调整它,我认为这是您的目标吗?
2021-05-02 09:36:50
事实证明,这是 httpd.conf 中的一个简单设置 - 但您的解决方案也适用。非常感谢(但 jQuery 更有趣)
2021-05-05 09:36:50
2021-05-11 09:36:50

您可以设置 $.ajax 传输来修改此处提到的设置:http : //www.henryalgus.com/reading-binary-files-using-jquery-ajax/

// use this transport for "binary" data type

$.ajaxTransport("+binary", function (options, originalOptions, jqXHR) {
    // check for conditions and support for blob / arraybuffer response type
    if (window.FormData && ((options.dataType && (options.dataType == 'binary')) || (options.data && ((window.ArrayBuffer && options.data instanceof ArrayBuffer) || (window.Blob && options.data instanceof Blob))))) {
        return {
            // create new XMLHttpRequest
            send: function (headers, callback) {
                // setup all variables
                var xhr = new XMLHttpRequest(),
                    url = options.url,
                    type = options.type,
                    async = options.async || true,
                    // blob or arraybuffer. Default is blob
                    dataType = options.responseType || "blob",
                    data = options.data || null,
                    username = options.username || null,
                    password = options.password || null;

                xhr.addEventListener('load', function () {
                    var data = {};
                    data[options.dataType] = xhr.response;
                    // make callback and send data
                    callback(xhr.status, xhr.statusText, data, xhr.getAllResponseHeaders());
                });

                xhr.open(type, url, async, username, password);

                // setup custom headers
                for (var i in headers) {
                    xhr.setRequestHeader(i, headers[i]);
                }

                xhr.responseType = dataType;
                xhr.send(data);
            },
            abort: function () {
                jqXHR.abort();
            }
        };
    }
});

然后让你的ajax调用:

return $.ajax({
    url: url,
    method: 'GET',
    dataType: 'binary',
    processData: 'false',
    responseType: 'arraybuffer',
    headers: { 'X-Requested-With': 'XMLHttpRequest' }
}).then(function (response) {
    var data = new Uint8Array(response);
    //do something with the data
    return data;
}, function (error) {
    alertify.error('There was an error! Error:' + error.name + ':' + error.status)
});
@VipulDessai 感谢您的回复,它确实帮助解决了我遇到的一个问题,我无法弄清楚如何自行修复,并且在从多个 Excel 电子表格(以二进制格式 .xlsb 存储)加载数据方面工作得非常好,因为我无法使用任何 3rd 方库,例如我当时所在的 OpenXML。认为它在大约 35 秒内加载了大约 20 个文件,每个文件接近 1 MB,这对我尝试过的所有其他方法都是一个巨大的改进。
2021-04-27 09:36:50
最终,这是在 Jquery ajax 中拥有二进制文件的唯一方法。
2021-04-30 09:36:50
谢谢你的回答,马特!我尝试在 Vipul 上面描述的场景中使用它(从服务器获取数据并在浏览器中使用它)。到目前为止,它似乎有效,但有一个主要缺点。在您的示例中使用 'GET' ike 时,'options.data' 中不包含任何参数。通常 JQuery 处理将该参数转换为 url 的一部分。在这里,您必须自己完成,请参阅developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/...问题是,对“发送”的调用在请求正文中传输了“数据”,但 GET 没有正文。
2021-04-30 09:36:50
是的,这个方法肯定会下载任何二进制文件。只是好奇,您的项目是否涉及将二进制数据从服务器传输到客户端并将其加载到 Web 浏览器中?
2021-05-01 09:36:50
@VipulDessai 该项目实际上从 Sharepoint 目录加载了文件并将其保存在内存中
2021-05-14 09:36:50

如果必须使用jQuery,可以使用$.ajaxSetup()修改低级设置。

例子:

  // Set up AJAX settings for binary files:
  $.ajaxSetup({
    beforeSend: function (jqXHR, settings) {
      if (settings.dataType === 'binary') {
        settings.xhr().responseType = 'arraybuffer';
      }
    }
  })

  // Make the actual call:
  let result = await $.ajax({
    url: '/api/export/data',
    type: 'GET',
    contentType: 'application/json',
    dataType: 'binary',
    processData: false,
    headers: {
      token: localStorage.token,
    },
  });
抱歉:仍然失败,“没有从文本到二进制的转换”。
2021-04-21 09:36:50
因为我需要支持不允许您在 xhr.open() 之前设置 responseType 的 IE 11,所以我使用了 beforeSend() 来xhrFields: { responseType: 'arraybuffer' }代替。
2021-04-21 09:36:50
为我工作。不错的简洁解决方案。
2021-05-12 09:36:50