惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
Vulnerabilities – Threatpost
U
Unit 42
F
Fortinet All Blogs
aimingoo的专栏
aimingoo的专栏
P
Proofpoint News Feed
F
Full Disclosure
月光博客
月光博客
Engineering at Meta
Engineering at Meta
博客园_首页
The Register - Security
The Register - Security
G
Google Developers Blog
The Cloudflare Blog
博客园 - Franky
K
Kaspersky official blog
A
Arctic Wolf
Scott Helme
Scott Helme
C
Cisco Blogs
Hugging Face - Blog
Hugging Face - Blog
C
Check Point Blog
NISL@THU
NISL@THU
AI
AI
D
DataBreaches.Net
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Stack Overflow Blog
Stack Overflow Blog
Project Zero
Project Zero
The GitHub Blog
The GitHub Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
量子位
Vercel News
Vercel News
T
Tor Project blog
P
Privacy International News Feed
D
Docker
I
Intezer
L
LangChain Blog
P
Proofpoint News Feed
Security Latest
Security Latest
C
CXSECURITY Database RSS Feed - CXSecurity.com
T
Threatpost
博客园 - 聂微东
AWS News Blog
AWS News Blog
Martin Fowler
Martin Fowler
P
Privacy & Cybersecurity Law Blog
V
V2EX
Last Week in AI
Last Week in AI
C
Cybersecurity and Infrastructure Security Agency CISA
The Hacker News
The Hacker News
T
Tenable Blog
Blog — PlanetScale
Blog — PlanetScale
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tailwind CSS Blog

博客园 - 反骨少年

cursor使用 wpf 进度条 https://docs.ultralytics.com/zh/tasks/detect/#export 博文阅读密码验证 - 博客园 博文阅读密码验证 - 博客园 博文阅读密码验证 - 博客园 博文阅读密码验证 - 博客园 vue 前端导出excel 通过outxml 复制sheet ,不完整 SVN提交过滤忽略的文件 博文阅读密码验证 - 博客园 OpenTelemetry 博文阅读密码验证 - 博客园 vue3+ElementPlus 后台布局搭建 IdentityServer4 canal管理 数据同步 Canal数据同步Kafka Xcode的思想,以及能让我学习的规范 阿里云的CICD
vue+.netCore 下载导出文件
反骨少年 · 2025-04-01 · via 博客园 - 反骨少年

一、 下载

后端代码

/// <summary>
/// 异步导出投诉报告
/// </summary>
/// <param name="exportParams">投诉报告查询参数</param>
/// <returns>文件流响应</returns>
[Route("/qms/complain/export/report")]
[HttpPost]
[Core.Filter.IgnoreActionLog] // 忽略日志记录
public async Task<IActionResult> ExportComplaintReportAsync([FromBody] ComplaintReportDto exportParams)
{
    // 获取文件流和文件名
    var complaintReportService = new ComplaintReportService(GetUserDBConnection());
    var userName = GetUserName();
    var (fileStream, fileName) = await complaintReportService.ExportComplaintReportAsync(exportParams, userName);

    // 重置文件流位置
    fileStream.Position = 0;

    // 允许前端获取 Content-Disposition 响应头
    Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");

    // 返回文件流
    return File(fileStream, "application/octet-stream", fileName);
}

前端代码

/**
 * 通用文件下载方法
 * 
 * @param {string} url 请求地址
 * @param {object} params 请求参数
 * @param {object} options 配置选项,可选(method, headers, responseType)
 * @returns {Promise} 返回完整响应体(包含文件流)
 * 
 * 示例:
 * downloadFile('/api/download', { id: 1 })
 *   .then(response => {
 *     // 处理下载的文件流
 *   })
 */
export function downloadFile(url, params, options = {}) {
  const {
    method = 'POST',
    headers = {
      'Content-Type': 'application/json'
    },
    responseType = 'blob',
  } = options;

  const token = getAccessToken() || getToken();

  // 创建独立的axios实例,避免全局拦截器干扰
  const instance = axios.create({
    baseURL: process.env.VUE_APP_BASE_API,
    timeout: 300000,
    headers: {
      ...headers,
      ...(token ? { 'Authorization': 'Bearer ' + token } : {})
    },
    responseType,
  });

  const config = {
    url,
    method,
  };

  if (method.toUpperCase() === 'GET') {
    config.params = params;
  } else {
    config.data = params;
  }

  return instance.request(config)
    .then(response => {
      return response; // 返回完整响应体,包含 headers、status、data
    })
    .catch(error => {
      return Promise.reject(error);
    });
}

 调用下载

    /**
     * 下载文件
     * @param {Object} response 响应对象
     */
    downloadFile(response) {
      const contentDisposition = response.headers['content-disposition'] || '';
      const filenameRegex = /filename\*=UTF-8''([^;]+)/;
      const match = filenameRegex.exec(contentDisposition);

      if (!match) {
        console.error('未获取到文件名,下载中止');
        return;
      }

      const filename = decodeURIComponent(match[1]);
      const blob = response.data;
      const url = URL.createObjectURL(blob);

      const link = document.createElement('a');
      link.href = url;
      link.download = filename;
      link.style.display = 'none';
      document.body.appendChild(link);

      link.click();
      URL.revokeObjectURL(url);
      document.body.removeChild(link);
    },
/**
 * 通过POST请求获取文件
 * 
 * 使用POST方法向文件接口提交查询参数,获取文件流(适用于参数较多或复杂的场景)
 * 
 * @param {Object} queryData - POST请求的查询参数对象
 * @returns {Promise<Blob>} 返回文件流的Promise对象,resolved值为Blob类型
 * 
 * 示例:
 * getFileByPost({ id: '123', type: 'report' })
 *   .then(response => {
 *     // 处理文件流(预览或下载)
 *     handleFileResponse(response);
 *   })
 */
export function getFileByPost(queryData) {
  // 显式指定method为POST,与函数功能保持一致
  return downloadFile('/wms/file/getfile', queryData, { method: 'POST' });
}

/**
 * 下载文件(GET方式)
 * 
 * 使用GET方法向文件接口传递查询参数,获取文件流
 * 适用于参数简单、长度有限的场景
 * 
 * @param {Object} queryParams - GET请求的查询参数对象(会转为URL查询字符串)
 * @returns {Promise<Blob>} 返回文件流的Promise对象
 * 
 * 示例:
 * getFileByGet({ fileId: '123', type: 'preview' })
 *   .then(response => {
 *     // 处理文件流(预览或下载)
 *   })
 */
export function getFileByGet(queryParams) {
  // 显式指定method为GET,参数会自动作为URL查询参数
  return downloadFile('/wms/file/getfile', queryParams, { method: 'GET' });
}

 接口调用

https://blog.51cto.com/u_16213413/12422025

https://blog.csdn.net/weixin_43118088/article/details/128852084