最近在做一个功能,是调用一个后台接口实现excel表格下载的功能。后端返回的是文件流,前端采用的是jquery ajax。
记录一下整个思考过程,仅供参考。
接口调通之后,可以看到浏览器中返回值有内容,但是为乱码,同时ajax的success、error方法中没有打印出数据。
网上查询看到,需要设置responseType,根据网上提示,修改代码为
$.ajax({
url: "接口地址",
type: "GET",
dataType: 'JSON',
contentType:"application/json;charset=UTF-8",
async: true,
data: params,
xhrFields: {
responseType: Blob
},
success: function(data) {
console.log('success',data)
}
经过修改后,提示responseText只支持类型为’’,或者类型为’text’
于是删除对responseType的设置,增加complete,进行状态查看。
complete: function(XMLHttpRequest, textStatus) {
console.log(XMLHttpRequest,textStatus)
},
显示readyState 为4, “parsererror” ,查阅发现,因为后端返回的数据类型和前端请求中dataType的要求类型不一致。
解决方法:将dataType注释掉
此时
在ajax的success中没有打印出内容,但是在complete中的 responseText中可以看到乱码内容。查询得知,可以使用dataFilter
对返回值进行预处理。
添加代码
dataFilter: function(data,type) {
console.log('dataFilter',data,type)
var result = new Blob(['\uFEFF'+ data], {type: 'text/plain;charset=utf-8'})
return result
}
此时success函数中终于可以打印返回的data了。
接下来开始实现下载:
方式1:
var reader = new FileReader();
reader.readAsDataURL(result); // 转换为base64,可以直接放入a表情href
reader.readAsArrayBuffer(result)
reader.onload = function (e) {
console.log('678',e.target.result)
// 转换完成,创建一个a标签用于下载
var downloadTag = document.createElement('a');
downloadTag.download = 'data';
downloadTag.href = e.target.result;
downloadTag.id = 'yydownload';
$("body").append(downloadTag);
// 修复firefox中无法触发click
console.log(downloadTag)
downloadTag.click()
$(downloadTag).remove();
}
方式2
const url = window.URL.createObjectURL(data)
const link = document.createElement('a')
link.href = url
link.setAttribute('download', 'name')
document.body.appendChild(link)
link.click()
console.log(link)
方式3
var params= {参数列表}
var form = $(");
form.attr('style', 'display:none');
form.attr('target', '');
form.attr('method', 'get');
var url = '后台地址';
form.attr('action', url);
$('body').append(form);
for(let i in params) {
var input = $('');
input.attr('type', 'hidden');
input.attr('name', i);
input.attr('value', params[i]);
form.append(input);
}
form.submit();
form.remove();
$('#downloadForm').remove();
直接报500,因为请求需要一个自定义请求头。
经过思考,认为是由于jquery自动把返回信息进行了转码,导致我即使在预处理阶段拿到的值都不是原始值,所以后续操作都在错误的基础上。
最终解决:
/* 原生ajax */
var str;
for(let i in params) {
str = `${str}&${i}=${params[i]}`
}
console.log(str)
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.open("get",`/df/pay/businessbill/batchExportData.do?${str}`,true);
xhr.setRequestHeader('x-function-id',ip.getMenuId())
xhr.onreadystatechange=function(){
console.log('状态改变了')
if(xhr.readyState==4){
if((xhr.status>=200 && xhr.status<300) || xhr.status==304){
var blob = this.response;
var url = window.URL.createObjectURL(blob);
window.open(url)
}else{
alert("请求失败!");
}
}
};
xhr.send();
下载方式:
下载
window.open(后端返回的地址)
或者window.location.href
。(常用)。FileReader
1 | readAsArrayBuffer(file) | 将文件读取为ArrayBuffer |
2 | readAsBinaryString(file) | 将文件读取为二进制字符串 |
3 | readAsDataURL(file) | 将文件读取为Data URL |
4 | readAsText(file, [encoding]) | 将文件读取为文本,encoding缺省值为'UTF-8' |
5 | abort() | 终止文件读取操作 |
/*
FileReader共有4种读取方法:
1.readAsArrayBuffer(file):将文件读取为ArrayBuffer。
2.readAsBinaryString(file):将文件读取为二进制字符串
3.readAsDataURL(file):将文件读取为Data URL
4.readAsText(file, [encoding]):将文件读取为文本,encoding缺省值为'UTF-8'
5.abort() 终止文件读取操作
*/
前端本地读取excel
需要本地服务器
<body>
<input type="file"onchange="read(this)" id="upload"/>
<script type="text/javascript">
function read(e){
var file = document.querySelector("#upload").value
// var files = tar.target.files[0];
var fileReader = new FileReader();
fileReader.onload = function(ev) {
console.log(ev)
var data = ev.target.result;
var wb;
wb = XLSX.read(btoa(fixdata(data)), {//手动转化
type: 'base64'
});
var persons = []; // 存储获取到的数据
var truckInfos = new Array() ;
persons = persons.concat(XLSX.utils.sheet_to_json(wb.Sheets["Sheet1"]));
alert(1);
angular.forEach(persons,function(data,idx){
});
}
// 以二进制方式打开文件
// fileReader.readAsBinaryString(file);
// fileReader.readAsArrayBuffer(file);
fileReader.readAsText(file)
}
</script>
</body>
//字符串转字符串ArrayBuffer
function str2ab(s,f) {
var b = new Blob([s],{type:‘text/plain’});
var r = new FileReader();
r.readAsArrayBuffer(b);
r.onload = function (){if(f)f.call(null,r.result)}
}
//ArrayBuffer转字符串
function ab2str(u,f) {
var b = new Blob([u]);
var r = new FileReader();
r.readAsText(b, 'utf-8');
r.onload = function (){if(f)f.call(null,r.result)}
}
var reader = new FileReader();
reader.readAsDataURL(result); // 转换为base64,可以直接放入a表情href
// reader.readAsText(result)
reader.onload = function (e) {
console.log('678',e.target.result)
// 转换完成,创建一个a标签用于下载
var downloadTag = document.createElement('a');
downloadTag.download = 'data';
downloadTag.href = e.target.result;
downloadTag.id = 'yydownload';
$("body").append(downloadTag); // 修复firefox中无法触发click
console.log(downloadTag)
downloadTag.click()
$(downloadTag).remove();
}
const link = document.createElement('a')
link.href = url
link.setAttribute('download', '7777')
document.body.appendChild(link)
link.click()
console.log(link)
文件读取
$('#yyid').change(function(e){
var file = e.target.files[0];//获取文件
var reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function(e){
let buffer = e.target.result //此时是arraybuffer类型
let hex = buf2hex(buffer)
console.log(Object.prototype.toString.call (buffer) );
// console.log(hex) //自行处理
// console.log(Object.prototype.toString.call (hex) );
const url = window.URL.createObjectURL(new Blob(['\uFEFF'+buffer], {type: 'text/plain;charset=utf-8'}))
// const url = window.URL.createObjectURL(hex);
const link = document.createElement('a')
link.href = url
link.setAttribute('download', '5555555')
document.body.appendChild(link)
link.click()
}
function buf2hex(buffer) {
// buffer is an ArrayBuffer
return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
}
})
jquery.form的ajaxsubmit提交时添加一个自定义头部header