前端实现下载功能汇总(下载二进制流文件、数组下载成csv、将十六进制下载成pcap、将文件下载成zip)

前言:汇总一下做过的下载功能,持续补充中

一、将后端传过来的二进制流文件下载(需要提取headers里面的文件名)

javascript 复制代码
const { herders,data }=res;
// 创建下载链接元素
const link = document.createElement("a");

// 创建 Blob 对象,将服务器响应的数据作为 Blob 的内容
const blob = new Blob([data], { type: "application/vnd.ms-excel" });

// 解析服务器响应头中的 Content-Disposition 字段获取文件名
var patt = new RegExp("filename=([^;]+\\.[^\\.;]+);*");
var contentDisposition = decodeURI(headers["content-disposition"]);
var result = patt.exec(contentDisposition);
var fileName = result[1];
fileName = fileName.replace(/\"/g, "");

// 隐藏下载链接元素
link.style.display = "none";

// 设置下载链接的属性
link.href = URL.createObjectURL(blob);
link.setAttribute("download", fileName);

// 将下载链接添加到页面中
document.body.appendChild(link);

// 模拟点击下载链接
link.click();

// 移除下载链接元素
document.body.removeChild(link);

以上代码可以直接copy进你的点击事件,然后根据你和后端约定的稍微改一下就行

需要理解的点:

1、res是后端传给我的数据,data是二进制流文件,headers里面有我需要的文件名,所以我将他们提取出来了;

2、创建blob时的type是用来指定不同的媒体类型(MIME),就是你要下载什么文件,我上面例子写的application/vnd.ms-excel就是微软 Excel 文件,那么就会下载成一个excel文件;

其他常见的MIME类型:

  • text/plain:纯文本文件,通常用于 .txt 文件。
  • text/html:HTML 文件,用于网页文档。
  • application/json:JSON 数据,用于传输和存储结构化数据。
  • application/pdf:PDF 文件,用于可移植文档格式。
  • image/jpeg:JPEG 图像文件。
  • image/png:PNG 图像文件。
  • audio/mp3:MP3 音频文件。
  • video/mp4:MP4 视频文件。

这只是一小部分常见的MIME类型,实际上有很多种不同的MIME类型,每种类型对应不同的文件格式或媒体类型,要根据需要来选择。

3、这些是用正则去卡文件名的操作,需要根据你的需求灵活变动

二、将后端传过来的二进制流文件下载(不需要提取文件名,前端来决定下载下来的文件叫什么

javascript 复制代码
          //创建 Blob 对象
          const blob = new Blob([row.traffic_meta], { type: "text/plain" });

          // 创建下载链接
          const url = URL.createObjectURL(blob);

          // 创建下载按钮
          const downloadLink = document.createElement("a");
          downloadLink.href = url;
          downloadLink.download = "example.txt"; // 设置下载文件的文件名

          // 将按钮添加到页面中
          document.body.appendChild(downloadLink);

          // 模拟点击下载链接
          downloadLink.click();

          // 移除下载按钮
          document.body.removeChild(downloadLink);

以上代码没有取后端传的文件名,是前端自己定义的,row.traffic_meta是二进制流文件,用的时候记得替换

三、将表格数据(数组)下载成csv文件

1、需求描述:下载一个表格,但是后端不传二进制文件流,而是接口返回给前端的数组。

类似这样的数据:

const tableData=[

{name: '1',value: 1},

{name: '2',value: 2},

{name: '3',value: 3},

{name: '4',value: 4},

{name: '5',value: 5},

{name: '6',value: 6},

{name: '7',value: 7},

]

要下载成一个csv,表头就是name和value

2、在utils创建一个js文件Export2Csv.js:

javascript 复制代码
function processRow(row) {
  let finalVal = ''
  for (let j = 0; j < row.length; j++) {
    let innerValue = row[j] === null ? '' : row[j].toString()
    if (row[j] instanceof Date) {
      innerValue = row[j].toLocaleString()
    }

    let result = innerValue.replace(/"/g, '""')
    if (result.search(/("|,|\n)/g) >= 0) { result = '"' + result + '"' }
    if (j > 0) { finalVal += ',' }
    finalVal += result
  }
  return finalVal + '\n'
}

export function exportToCsv(filename, rows) {
  let csvFile = ''
  for (let i = 0; i < rows.length; i++) {
    csvFile += processRow(rows[i])
  }
  // 添加\ufeff头,标识excel可以打开UTF8编码的文件
  const blob = new Blob(['\ufeff', csvFile], { type: 'text/csv;charset=utf-8;' })
  if (navigator.msSaveBlob) { // IE 10+
    navigator.msSaveBlob(blob, filename)
  } else {
    const link = document.createElement('a')
    if (link.download !== undefined) { // feature detection
      // Browsers that support HTML5 download attribute
      const url = URL.createObjectURL(blob)
      link.setAttribute('href', url)
      link.setAttribute('download', filename)
      link.style.visibility = 'hidden'
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link)
    }
  }
}

export function exportToCsv_zl(filename, rows) {
  let csvFile = ''
  for (let i = 0; i < rows.length; i++) {
    csvFile += processRow(rows[i])
  }
  // 添加\ufeff头,标识excel可以打开UTF8编码的文件
  // const blob= new Blob(['\ufeff', csvFile], { type: 'text/csv;charset=utf-8;' })
  console.log(csvFile);
  return csvFile
}

export function exportDictArray2csv(data, filename,zl) {
  const keys = Object.keys(data[0])

  const rows = []

  // writer header
  rows.push(keys)

  data.forEach(dict => {
    const row = []
    keys.forEach(key => {
      row.push(dict[key])
    })
    rows.push(row)
  })
  if(zl){
   return exportToCsv_zl(filename,rows)
  }else{
    exportToCsv(filename, rows)
  }
  
}

export default exportDictArray2csv

3、 导入在需要该功能的页面里使用

javascript 复制代码
import { exportDictArray2csv } from "@/utils/Export2Csv.js";


const filename = `data.csv`;
exportDictArray2csv(tableData.value, filename);

四、将16进制转化为pcap包并下载

1、方法代码:

javascript 复制代码
// 将十六进制字符串转换为字节数组
function hexToBytes(hex) {
  const bytes = [];
  for (let i = 0; i < hex.length; i += 2) {
    bytes.push(parseInt(hex.substr(i, 2), 16));
  }
  return new Uint8Array(bytes);
}

// 构建 PCAP 文件头
function createPcapHeader() {
  const header = new Uint8Array(24);
  const dataView = new DataView(header.buffer);

  dataView.setUint32(0, 0xa1b2c3d4, true); // magic number
  dataView.setUint16(4, 2, true); // version major
  dataView.setUint16(6, 4, true); // version minor
  dataView.setUint32(8, 0, true); // timezone
  dataView.setUint32(12, 0, true); // sigfigs
  dataView.setUint32(16, 65535, true); // snaplen
  dataView.setUint32(20, 1, true); // linktype

  return header;
}

// 创建 PCAP 数据包(这里仅作为示例,你需要根据具体数据填充)
function createPcapPacket(data) {
  const packetHeader = new Uint8Array(16);
  const dataView = new DataView(packetHeader.buffer);

  const timestamp = Math.floor(Date.now() / 1000); // 当前时间戳
  const microseconds = (Date.now() % 1000) * 1000; // 微秒部分
  const length = data.length;

  dataView.setUint32(0, timestamp, true); // seconds
  dataView.setUint32(4, microseconds, true); // microseconds
  dataView.setUint32(8, length, true); // number of octets of packet saved in file
  dataView.setUint32(12, length, true); // actual length of the packet

  return { header: packetHeader, data };
}

// 主函数
function createPcapFile(hexString) {
  const pcapHeader = createPcapHeader();
  const packetData = hexToBytes(hexString);
  const pcapPacket = createPcapPacket(packetData);

  // 拼接 PCAP 文件内容
  const pcapFile = new Uint8Array(
    pcapHeader.length + pcapPacket.header.length + pcapPacket.data.length
  );
  pcapFile.set(pcapHeader, 0);
  pcapFile.set(pcapPacket.header, pcapHeader.length);
  pcapFile.set(pcapPacket.data, pcapHeader.length + pcapPacket.header.length);

  return pcapFile;
}

2、使用该方法:

javascript 复制代码
          const pcapFile = createPcapFile(pkt_data);
          const blob1 = new Blob([pcapFile], { type: "application/octet-stream" });
          // 创建下载链接
          const url = URL.createObjectURL(blob1);

          // 创建下载按钮
          const downloadLink = document.createElement("a");
          downloadLink.href = url;
          downloadLink.download = "命中流量.pcap"; // 设置下载文件的文件名

          // 将按钮添加到页面中
          document.body.appendChild(downloadLink);

          // 模拟点击下载链接
          downloadLink.click();

          // 移除下载按钮
          document.body.removeChild(downloadLink);

五、将两个文件合成zip下载

1、先下载插件

javascript 复制代码
npm i jszip

2、导入并使用

javascript 复制代码
      import JSZip from "jszip";
      import { saveAs } from "file-saver";

      const blob1 = res.data;
      const blob2 = new Blob(
        ["\ufeff", exportDictArray2csv([row], "filename.csv", true)],
        { type: "text/csv;charset=utf-8;" }
      );
      const zip = new JSZip();
      // 将 blob 数据添加到 ZIP 文件
      zip.file(`原始流量.pcap`, blob1);
      zip.file("告警事件.csv", blob2);

      // 生成 ZIP 文件
      const zipBlob = await zip.generateAsync({ type: "blob" });
      saveAs(zipBlob, "files.zip");

以上代码就是将两个bolb传入插件并下载成了一个zip,解压之后就是:

相关推荐
挣扎与觉醒中的技术人15 分钟前
【技术干货】三大常见网络攻击类型详解:DDoS/XSS/中间人攻击,原理、危害及防御方案
前端·网络·ddos·xss
zeijiershuai20 分钟前
Vue框架
前端·javascript·vue.js
写完这行代码打球去22 分钟前
没有与此调用匹配的重载
前端·javascript·vue.js
华科云商xiao徐22 分钟前
使用CPR库编写的爬虫程序
前端
狂炫一碗大米饭25 分钟前
Event Loop事件循环机制,那是什么事件?又是怎么循环呢?
前端·javascript·面试
IT、木易26 分钟前
大白话Vue Router 中路由守卫(全局守卫、路由独享守卫、组件内守卫)的种类及应用场景
前端·javascript·vue.js
顾林海27 分钟前
JavaScript 变量与常量全面解析
前端·javascript
程序员小续27 分钟前
React 组件库:跨版本兼容的解决方案!
前端·react.js·面试
乐坏小陈28 分钟前
2025 年你希望用到的现代 JavaScript 模式 【转载】
前端·javascript
生在地上要上天28 分钟前
从600行"状态地狱"到可维护策略模式:一次列表操作限制重构实践
前端