导出文件,能够导出但是文件打不开

背景:

在项目开发中,对于列表的查询,而后会有导出功能,这里导出的是一个excell表格。实现了两种,1.导出的文件,命名是前端传输过去的;2.导出的文件,命名是根据后端返回的文件名获取的。

 //解码获取导出文件名

        const fileNames = res.headers['content-disposition']

        const fileName = decodeURIComponent(fileNames.match(/=(.*)$/)[1])

//能够导出但是打不开,导出接口的网络请求要带上responseType: 'blob',

     //导出文件【get】

    exportCrewInfoFile(params) {

        return request.Get("/data/ferryShip/download?", params, {

            headers: {

                "Content-Type": "application/json",

            },

            responseType: 'blob',

        });

    },

    //导出文件【post】

    exportWarningFile(params) {

        return request.Post("/data/warningRecord/download", params, {

            headers: {

                "Content-Type": "application/json",

            },

            responseType: 'blob',

        });

    },

前端界面:

前端请求接口,axios发起网络请求:

axios封装:

import axios from "axios";
import useShoreBasedStore from "@/store";
import qs from 'qs';
import router from "@/router/index.js";
import { ElMessageBox } from "element-plus";

let messageBoxVisible = false
export const BASEUrl = import.meta.env.VITE_USER_NODE_ENV === 'development' ? '/apiproxy/pa' : import.meta.env.VITE_API_URL + '/pa'
const request = axios.create({
    baseURL: BASEUrl,
    timeout: 3000 * 60,
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
});

/**
 * 请求拦截添加token
 * */
request.interceptors.request.use((config) => {
    const user = useShoreBasedStore();
    if (user.userInfo.token) {
        config.headers.Authorization = user.userInfo.token;
    }
    return config;
}, (error) => {
    return Promise.reject(error)
});

const showMsg = () => {
    if (!messageBoxVisible) {
        messageBoxVisible = true
        const user = useShoreBasedStore()
        ElMessageBox.confirm(
            '您的登录信息已过期,请重新登录!',
            '温馨提示',
            {
                confirmButtonText: '确认',
                cancelButtonText: '取消',
                type: 'warning'
            }
        ).then(() => {
            user.loginOut()
            router.push({ name: 'login' })
        }).catch(() => {
        }).finally(() => {
            messageBoxVisible = false
        })
    }
}

request.interceptors.response.use((response) => {
    const data = response.data
    if (data.status === 401 || data.code === 401) {
        showMsg()
    } else {
        return response
    }
}, (error) => {
    if (error.response.data.code === 401) {
        showMsg()
    } else {
        return Promise.reject(error)
    }
})

// 定义get方法
request.Get = function (url, params, config) {
    if (params) {
        return request.get(url + qs.stringify(params), config);
    }
    return request.get(url, config);
};

// 定义post方式
request.Post = function (url, params, config) {
    if (params) {
        return request.post(url, params, config);
    }
    return request.post(url, config);
};

export default request;

接口:

import request from "../utils/request.js";

const fileApi = {
    // 上传文件
    uploadFile(params) {
        return request.Post("/data/file/upload", params, {
            headers: {
                "Content-Type": "multipart/form-data",
            },
        });
    },
    // 删除文件
    deleteFile(params) {
        return request.Post("/data/file/delete", params, {
            headers: {
                "Content-Type": "application/json",
            },
        });
    },
    //导出文件【get】
    exportFerryPortFile(params) {
        return request.Get("/data/ferryPort/download?", params, {
            headers: {
                "Content-Type": "application/json",
            },
            responseType: 'blob',
        });
    },
    //导出文件【post】
    exportWarningFile(params) {
        return request.Post("/data/warningRecord/download", params, {
            headers: {
                "Content-Type": "application/json",
            },
            responseType: 'blob',
        });
    },
}
export default fileApi;

导出封装的方法: 

/**
 *
 * @param {*} fileContent 文件本体
 * @param {*} _fileName 自定义文件名
 */
export const exportFileUtil = (fileContent, _fileName) => {
  const content = fileContent;
  const blob = new Blob([content], {
    type: fileContent.type || "application/octet-stream; charset=utf-8",
  });
  const fileName = _fileName;
  if ("download" in document.createElement("a")) {
    //非IE下载
    const a = document.createElement("a"); //创建一个a标签
    a.download = fileName; //指定文件名称
    a.style.display = "none"; //页面隐藏
    a.href = URL.createObjectURL(blob); // href用于下载地址
    document.body.appendChild(a); //插到页面上
    a.click(); //通过点击触发
    URL.revokeObjectURL(a.href); //释放URL 对象
    document.body.removeChild(a); //删掉a标签
  } else {
    //IE10 + 下载
    navigator.msSaveBlob(blob, fileName);
  }
};
/**
 * 
 * @param {*} res 接口返回的文件流
 */
export const dowloadFileUrl = (res) => {
  const fileNames = res.headers['content-disposition']
  if (fileNames) {
      //解码
      const fileName = decodeURIComponent(fileNames.match(/=(.*)$/)[1])
      // 处理返回的文件流
      const content = res.data
      const blob = new Blob([content], {
          type: res.data.type||"application/vnd.ms-excel"
      });
      if ('download' in document.createElement('a')) {
          //非IE下载
          const a = document.createElement('a') //创建一个a标签
          a.download = fileName //指定文件名称
          a.style.display = 'none' //页面隐藏
          a.href = URL.createObjectURL(blob) // href用于下载地址
          document.body.appendChild(a) //插到页面上
          a.click() //通过点击触发
          URL.revokeObjectURL(a.href) //释放URL 对象
          document.body.removeChild(a) //删掉a标签
      } else {
          //IE10 + 下载
          navigator.msSaveBlob(blob, fileName)
      }
  }
}

使用导出的方法:

//只是举例,根据实际进行调整
const exportExcel = () => {
  const search = searchForm.value.submitData();
  const params = {
    ...search,
  };
  api.fileApi
    .exportCrewInfoFile(params)
    .then((res) => {
      if (res.status === 200) {
        exportFileUtil(res.data, "渡口管理导出文件.xlsx");
        dowloadFileUrl(res)
      }
    })
    .finally((err) => {
      console.log(err);
    });
};

写到这儿,就实现了导出功能。。。下面的是导出接口的详细解释: 

 

一、导出文件使用get请求

(1)、导出文件,get请求里面传参有数组等复杂数据结构

前端界面:

上图可以看见post查询接口可以返回4条数据,那么导出功能以同样的参数也应该导出4条数据的excell。

导出传参:

结果:

导出文件但是打不开,原因可能是:传参的问题;接口返回的数据有问题。 

能够导出,不能打开文件。

 经过排查,是前端请求有问题,如下图:

能够导出,并且能够打开的。get请求的响应体和请求体的结构。如下:请求传参带上,responseType: 'blob',【必须带上】

二、导出文件使用post请求 

前端界面:

导出传参:

总结:

导出功能,不管前端使用的是get或者post请求,都需要后端对接受到的传参进行识别,进而返回对应的响应体。 

前端请求一定要带上responseType: 'blob',

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/952861.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

马斯克的Grok-2 Beta APP在苹果应用商店上限了,Grok-2安装尝鲜使用教程

马斯克的Grok-2 Beta APP 已经上线苹果商城了,移动端的Grok挺好用的!无需登录即可使用! (文末有安装教程) 实测之后,Grok-2 绘画方面个人感觉比GPT-4的绘画还要强一些。而且速度还挺快,可以多次…

《机器学习》——sklearn库中CountVectorizer方法(词频矩阵)

CountVectorizer方法介绍 CountVectorizer 是 scikit-learn 库中的一个工具,它主要用于将文本数据转换为词频矩阵,而不是传统意义上的词向量转换,但可以作为词向量转换的一种基础形式。用于将文本数据转换为词频矩阵,它是文本特征…

CV 图像处理基础笔记大全(超全版哦~)!!!

一、图像的数字化表示 像素 数字图像由众多像素组成,是图像的基本构成单位。在灰度图像中,一个像素用一个数值表示其亮度,通常 8 位存储,取值范围 0 - 255,0 为纯黑,255 为纯白。例如,一幅简单的…

支持向量回归(SVR:Support Vector Regression)用于A股数据分析、预测

简单说明 支持向量回归是一种用来做预测的数学方法,属于「机器学习」的一种。 它的目标是找到一条「最合适的线」,能够大致描述数据点的趋势,并允许数据点离这条线有一定的误差(不要求所有点都完全落在这条线上)。 可以把它想象成:找到一条「宽带」或「隧道」,大部分…

ollama教程(window系统)

前言 在《本地大模型工具哪家强?对比Ollama、LocalLLM、LM Studio》一文中对比了三个常用的大模型聚合工具优缺点,本文将详细介绍在window操作系统下ollama的安装和使用。要在 Windows 上安装并使用 Ollama,需要依赖 NVIDIA 显卡&#xff0c…

Flink系统知识讲解之:容错与State状态管理

Flink系统知识之:容错与State状态管理 状态在Flink中叫作State,用来保存中间计算结果或者缓存数据。根据是否需要保存中间结果,分为无状态计算和有状态计算。对于流计算而言,事件持续不断地产生,如果每次计算都是相互…

DolphinScheduler自身容错导致的服务器持续崩溃重大问题的排查与解决

01 问题复现 在DolphinScheduler中有如下一个Shell任务: current_timestamp() { date "%Y-%m-%d %H:%M:%S" }TIMESTAMP$(current_timestamp) echo $TIMESTAMP sleep 60 在DolphinScheduler将工作流执行策略设置为并行: 定时周期调度设置…

ASP.NET Core 实现微服务 - Elastic APM

这次要给大家介绍的是Elastic APM ,一款应用程序性能监控组件。APM 监控围绕对应用、服务、容器的健康监控,对接口的调用链、性能进行监控。在我们实施微服务后,由于复杂的业务逻辑,服务之间的调用会像蜘蛛网一样复杂。有了调用链…

25/1/12 嵌入式笔记 学习esp32

了解了一下位选线和段选线的知识: 位选线: 作用:用于选择数码管的某一位,例如4位数码管的第1位,第2位) 通过控制位选线的电平(高低电平),决定当前哪一位数码管处于激活状…

IMX6U Qt 开发环境

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一、交叉编译 1. 安装通用 ARM 交叉编译工具链 2. 安装 Poky 交叉编译工具链 二、编译出厂源码 1. U-boot 2. 内核和模块 3. 编译出厂 Qt GUI 综合 Demo 前言…

【Oracle专栏】2个入参,生成唯一码处理

Oracle相关文档,希望互相学习,共同进步 风123456789~-CSDN博客 1.背景 业务需要:2个参数,如 aidbankid ,两个值是联合主键,需要生成一个固定唯一码,长度有限制32位,为了…

跨界融合:人工智能与区块链如何重新定义数据安全?

引言:数据安全的挑战与现状 在信息化驱动的数字化时代,数据已成为企业和个人最重要的资产之一。然而,随着网络技术的逐步优化和数据量的爆发式增长,数据安全问题也愈变突出。 数据安全现状:– 数据泄露驱动相关事件驱…

给DevOps加点料:融入安全性的DevSecOps

从前,安全防护只是特定团队的责任,在开发的最后阶段才会介入。当开发周期长达数月、甚至数年时,这样做没什么问题;但是现在,这种做法现在已经行不通了。 采用 DevOps 可以有效推进快速频繁的开发周期(有时…

CDP中的Hive3之Hive Metastore(HMS)

CDP中的Hive3之Hive Metastore(HMS) 1、CDP中的HMS2、HMS表的存储(转换)3、HWC授权 1、CDP中的HMS CDP中的Hive Metastore(HMS)是一种服务,用于在后端RDBMS(例如MySQL或PostgreSQL&a…

【算法】判断一个链表是否为回文结构

问: 给定一个单链表的头节点head,请判断该链表是否为回文结构 例: 1 -> 2 -> 1返回true;1 -> 2 -> 2 -> 1返回true;15 -> 6 -> 15返回true 答: 笔试:初始化一个栈用来…

Python双指针

双指针 双指针:在区间操作时,利用两个下标同时遍历,进行高效操作 双指针利用区间性质可以把 O ( n 2 ) O(n^2) O(n2) 时间降低到 O ( n ) O(n) O(n) 反向扫描 反向扫描: l e f t left left 起点,不断往右走&…

VMware虚拟机安装Home Assistant智能家居平台并实现远程访问保姆级教程

目录 前言 1. 安装Home Assistant 前言 本文主要介绍如何在windows 10 上用VMware Workstation 17 Pro搭建 Home Assistant OS Host os version:Windows 10 Pro, 64-bit (Build 19045.5247) 10.0.19045 VMware version:VMware Workstation 17 Pro 1. 安装Home …

【MySQL】SQL菜鸟教程(一)

1.常见命令 1.1 总览 命令作用SELECT从数据库中提取数据UPDATE更新数据库中的数据DELETE从数据库中删除数据INSERT INTO向数据库中插入新数据CREATE DATABASE创建新数据库ALTER DATABASE修改数据库CREATE TABLE创建新表ALTER TABLE变更数据表DROP TABLE删除表CREATE INDEX创建…

【Java回顾】Day5 并发基础|并发关键字|JUC全局观|JUC原子类

JUC全称java.util.concurrent 处理并发的工具包(线程管理、同步、协调) 一.并发基础 多线程要解决什么问题?本质是什么? CPU、内存、I/O的速度是有极大差异的,为了合理利用CPU的高性能,平衡三者的速度差异,解决办法…

自然语言转 SQL:通过 One API 将 llama3 模型部署在 Bytebase SQL 编辑器

使用 Open AI 兼容的 API,可以在 Bytebase SQL 编辑器中使用自然语言查询数据库。 出于数据安全的考虑,私有部署大语言模型是一个较好的选择 – 本文选择功能强大的开源模型 llama3。 由于 OpenAI 默认阻止出站流量,为了简化网络配置&#…