为什么 AJAX 输出带有错误的编码

Why does AJAX output comes with wrong encoding?

本文关键字:编码 有错误 输出带 AJAX 为什么      更新时间:2023-09-26

>我正在使用AJAX(Angular)从服务器获取文件。该文件是一个简单的XLSX document,发送方式如下:

ob_start();
$file = 'PHPExcel_IOFactory::createWriter($xls, 'Excel2007');
$file->save('php://output');
$response->setContent(ob_get_clean());
$response->headers->replace(array(
    'Content-Type'          => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    'Content-Disposition'   => 'attachment;filename=file.xlsx"'
));

当我从前端发出请求时,我也使用接受标头。然后我使用 FileSaver.js 和 Blob.js 使用角度文件保护程序保存文件。但是收到的文件已损坏,我无法在Excel中打开它:它的大小(例如)为12446字节,但Chrome的DevTools Network选项卡将响应内容长度标头显示为7141字节。

如何解决这个问题?

上级:我发送这样的请求:

$http.get(baseURL + '/' + entity + '/export/?' + condition + sort, {
          headers: {'Accept': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=utf-8'}
        });

并像这样下载文件:

var data = new Blob([response.data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'});
          FileSaver.saveAs(data, 'file.xlsx');

我解决这个问题的方法是使用普通的 JS AJAX,而不是 AngularJS。(AngularJS和JQuery处理二进制响应可能存在问题。

这应该有效:

var request = new XMLHttpRequest();
request.open('GET', 'http://yourserver/yourpath', true);
request.responseType = 'blob';
request.onload = function (e) {
    if (this.status === 200) {
        var blob = this.response;
        if (window.navigator.msSaveOrOpenBlob) {
            var fileNamePattern = /filename[^;='n]*=((['"]).*?'2|[^;'n]*)/;
            window.navigator.msSaveBlob(blob, fileNamePattern.exec(request.getResponseHeader("content-disposition"))[1]);
        } else {
            var downloadLink = window.document.createElement('a');
            var contentTypeHeader = request.getResponseHeader("Content-Type");
            var b = new Blob([blob], { type: contentTypeHeader });
            downloadLink.href = window.URL.createObjectURL(b);
            var fileNamePattern = /filename[^;='n]*=((['"]).*?'2|[^;'n]*)/;
            downloadLink.download = fileNamePattern.exec(request.getResponseHeader("content-disposition"))[1];
            document.body.appendChild(downloadLink);
            downloadLink.click();
            document.body.removeChild(downloadLink);
            window.URL.revokeObjectURL(b);
        }
    }
};
request.send();

代码基于这个和这个。

仅供参考,我发现当response.data不是作为blob返回而是text/plainapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet时,new Blob([response.data], ...)返回的大小几乎是response.data大小的两倍。要绕过它,您需要向它传递一个字节数组:

    var i, l, d, array;
    d = this.result;
    l = d.length;
    array = new Uint8Array(l);
    for (var i = 0; i < l; i++){
        array[i] = d.charCodeAt(i);
    }
    var b = new Blob([array], {type: 'application/octet-stream'});
    window.location.href = URL.createObjectURL(b);

代码来自这里。

无论如何,由于使用AngularJS的AJAX响应不正确,因此您将无法以这种方式获得有效的xlsx文件。你需要使用香草JS。