Antd Upload 组件上传文件接收数据流并下载

Elysian
2021-10-22 / 0 评论 / 1,059 阅读 / 正在检测是否收录...

一、应用场景
主要是需要上传一个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放到对应的下载标签中就可以了。

0

评论

博主关闭了所有页面的评论