一、应用场景
主要是需要上传一个PDF文件,然后服务器会针对PDF文件,转换成WORD文件,然后返回WORD文件的下载流。
二、解决方法
1、默认情况下Antd的Upload组件上传文件后接收服务端返回的字符串,再返回给fileList,如果服务端返回二进制文件流,则Upload组件接收的也是二进制流的乱码字符串。
2、JS接收流文件然后提供下载,主流是使用 blob对象
来将流转变为blob地址,然后提供下载。
3、Ajax默认情况下,如果不设置responseType为blob则返回的内容就是字符串,但是直接返回的二进制流,转换成 blob对象
会造成数据损坏,查了资料说是utf8编码等之类的问题引起的,所以就需要设置 responseType='blob'
或者是 'arraybuffer'
然后转换为 blob对象
。
4、antd的Upload组件,正好提供了一个 customRequest
属性可以自定义ajax请求。
基于上述4点,我们只需要修改组件的 customRequest
属性,就可以实现应用场景
具体customRequest
属性代码如下:
customRequest(option) {
const getError = (option, xhr) => {
var msg = "cannot ".concat(option.method, " ").concat(option.action, " ").concat(xhr.status, "'");
var err = new Error(msg);
err.status = xhr.status;
err.method = option.method;
err.url = option.action;
return err;
}
const getBody = (xhr) => {
debugger;
if (xhr.responseType && xhr.responseType !== 'text') {
return xhr.response;
}
var text = xhr.responseText || xhr.response;
if (!text) {
return text;
}
try {
return JSON.parse(text);
} catch (e) {
return text;
}
}
// eslint-disable-next-line no-undef
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
if (option.onProgress && xhr.upload) {
xhr.upload.onprogress = function progress(e) {
if (e.total > 0) {
e.percent = e.loaded / e.total * 100;
}
option.onProgress(e);
};
} // eslint-disable-next-line no-undef
var formData = new FormData();
if (option.data) {
Object.keys(option.data).forEach(function (key) {
var value = option.data[key]; // support key-value array data
if (Array.isArray(value)) {
value.forEach(function (item) {
// { list: [ 11, 22 ] }
// formData.append('list[]', 11);
formData.append("".concat(key, "[]"), item);
});
return;
}
formData.append(key, option.data[key]);
});
} // eslint-disable-next-line no-undef
if (option.file instanceof Blob) {
formData.append(option.filename, option.file, option.file.name);
} else {
formData.append(option.filename, option.file);
}
xhr.onerror = function error(e) {
option.onError(e);
};
xhr.onload = function onload() {
// allow success when 2xx status
// see https://github.com/react-component/upload/issues/34
if (xhr.status < 200 || xhr.status >= 300) {
return option.onError(getError(option, xhr), getBody(xhr));
}
return option.onSuccess(getBody(xhr), xhr);
};
xhr.open(option.method, option.action, true); // Has to be after `.open()`. See https://github.com/enyo/dropzone/issues/179
if (option.withCredentials && 'withCredentials' in xhr) {
xhr.withCredentials = true;
}
var headers = option.headers || {}; // when set headers['X-Requested-With'] = null , can close default XHR header
// see https://github.com/react-component/upload/issues/33
if (headers['X-Requested-With'] !== null) {
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
}
Object.keys(headers).forEach(function (h) {
if (headers[h] !== null) {
xhr.setRequestHeader(h, headers[h]);
}
});
xhr.send(formData);
return {
abort: function abort() {
xhr.abort();
}
};
},
修改上述属性后,则onChange等方法接收到的file或者fileList中的response则变为blob对象,然后将blob对象输出url放到对应的下载标签中就可以了。
评论