XMLHttpRequest下载文件方法中添加处理服务器返回json格式的错误提示信息

Posted stone2012

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XMLHttpRequest下载文件方法中添加处理服务器返回json格式的错误提示信息相关的知识,希望对你有一定的参考价值。

本篇随笔说明

警告:本文不适合找“XMLHttpRequest下载文件方法”的人群阅读(尽管我的标题包含了这些关键字),这个人群看了本文后可能会有些懵。

这里没有完整的XMLHttpRequest下载文件的代码,只是为了解决特定问题而摘出来部分代码,因是从项目中提取的,故代码中也包含了用到的一些其它框架。

 

问题描述

在下载文件的程序中,此处我们用到的是excel导出,此时如果服务器没有合适的数据可以供导出,我们原来的方案,就是导出一个只含有头部列头的excel,在前端还是依然能够下载该文件,用户看到一个不含他想要的数据的文件,大概会懵掉,对用户不太友好。后来想着,要不就把错误提示扔到excel里,想想还是不友好,以致有了下面的改进方案:

解决方案

在没有合适数据可导出或发生一些可预知的错误时,服务器返回一个错误提示的json数据。此时前后端需要进行一些调整,如下。

用XMLHttpRequest下载文件,所以设置XMLHttpRequest.responseType = "blob",此时如果服务器返回一个json数据,前端无法通过一般的方案解析出json数据;
解决方案:服务器端返回一个特定的http状态码,前端遇到该状态码,则进行特殊处理。
后端返回一个206的错误码及一个json数据
       //为了更清晰的说明问题,此处把其它代码都去掉了,只保留返回错误情况的代码
 public IActionResult GetPBbackDtoPrintListForPB(GetWorkTimeArrangeInput args)
        {

                Response.StatusCode = 206;
                string msg = "没有数据!请确保筛选条件下有数据!";
                return Json(new BizResult(){ Success = false, Message = msg });
            }

前端处理json的部分,不能像正常返回json数据那样用JSON.parse(result)处理,或直接result.success,因为这样是取不到数据的,且运行会有未定义的错误。需要用如下方法,从流中读取。

            if (this.status === 206) {//处理错误提示
                var result = this.response;
                if (result.type === ‘application/json‘) {
                    var reader = new FileReader();
                    reader.readAsText(result, ‘utf-8‘);
                    reader.onload = (e) => {
                        var jsonData = JSON.parse(reader.result);
                        if (!jsonData.success) {
                            $.messager.alert("警告", jsonData.message);
                        }
                    }
                }

 

相对完整的前端代码,因用到其它JS框架,如用不上需剔除部分代码,还有一些传值封装,代码太多,而且分散在各处,这里不全部列出来

    /**
     * 异步下载文件 依赖easyui的进度条
     *
     */
    downloadAsync: function (method, url, data,contentType, displayfileName, callback) {
        if (!displayfileName)
            displayfileName = ‘‘;
        if (!method)
            method = "get";
        method = method.toLowerCase();
        if (!url)
            throw "url mast has value";

        if (method != "post" && method != "get")
            method = "get";
        var xhr = new XMLHttpRequest();

        var sendData = null;
        if (data && (typeof (data) == "object" || typeof (data) == "string")) {
            if (contentType.toLowerCase() ==="application/json") {
                sendData = JSON.stringify(data);
            } else if (method.toLowerCase() === "get") {
                //参数追加到url上
                var params;
                if (typeof (data) == "string")
                    params = data;
                else
                    params = $.param(data);
                var ls = url.indexOf(url.length);
                switch (ls) {
                    case "?":
                    case "&":
                        url += params
                        break;
                    default:
                        if (url.indexOf(‘?‘) < 0) {
                            url += "?" + params;
                        } else {
                            url += "&" + params;
                        }
                        break;
                }
            } else {
                sendData = $.param(data);
            }
        }
        xhr.open(method, url, true);    // 也可以使用POST方式,根据接口       
        xhr.setRequestHeader(‘content-type‘, contentType);
        xhr.responseType = "blob";  // 返回类型blob

        $.messager.progress({ msg: ‘下载中。。。‘, interval: 0 });
        var bar = $.messager.progress(‘bar‘);

        //进度事件
        xhr.onprogress = function (ev) {
            if (ev.lengthComputable) {
                progress = ev.loaded / ev.total;
                //更新进度条
                bar.progressbar(‘setValue‘, parseFloat(progress, 2) * 100);
            }
        };

        // 定义请求完成的处理函数
        xhr.onload = function () {
            // 请求完成
            if (this.status === 200) {
                // 返回200
                var blob = this.response;
                var reader = new FileReader();
                reader.readAsDataURL(blob);  // 转换为base64,可以直接放入a表情href
                reader.onload = function (e) {
                    // 转换完成,创建一个a标签用于下载
                    var a = document.createElement(‘a‘);
                    if (!displayfileName || typeof (displayfileName) != ‘string‘)
                        displayfileName = new Date().getTime + ‘.txt‘;
                    console.log(displayfileName);
                    a.download = displayfileName;
                    a.href = e.target.result;
                    $("body").append(a);  // 修复firefox中无法触发click
                    a.click();
                    $(a).remove();
                    if (typeof (callback) == "function")
                        callback();
                };
            }
            else if (this.status === 206) {//处理错误提示
                var result = this.response;
                if (result.type === ‘application/json‘) {
                    var reader = new FileReader();
                    reader.readAsText(result, ‘utf-8‘);
                    reader.onload = (e) => {
                        var jsonData = JSON.parse(reader.result);
                        if (!jsonData.success) {
                            $.messager.alert("警告", jsonData.message);
                        }
                    }
                }
            }
            else {
                errortitle = "错误";
                error = "导出错误";
                switch (this.status) {
                    case 404:
                        error += " 页面找不到";
                        break;
                    case 400:
                        error += " 导出参数不对";
                        break;
                    case 500:
                        error += " 导出数据失败";
                        break;
                    default:
                        break;
                }
                $.messager.alert(errortitle, error);
            }
            $.messager.progress(‘close‘);
        };
        xhr.onreadystatechange = function (ev) {
        }
        // 发送ajax请求
        xhr.send(sendData);
    }

 

以上是关于XMLHttpRequest下载文件方法中添加处理服务器返回json格式的错误提示信息的主要内容,如果未能解决你的问题,请参考以下文章

Firefox 中的跨站点 XmlHttpRequest?

使用 new XMLHttpRequest() 制作下载文件进度条

js通过HEAD请求方式提前获取下载文件大小,XMLHttpRequest和ajax两种实例

XMLHttpRequest下载文件

Cordova XMLHttpRequest 文件下载

XMLHttpRequest下载文件,js下载文件,支持后台消息在前端页面提示