前端:文件直接在浏览器里下载

javascript 复制代码
/**
 * 下载文件
 */
downloadFile(row){
  window.open(window.location.origin + '/api' + row.accessUrl)
},

(1)问题原因

window.open() 方式的优点是简单直接,但在 权限验证、错误处理、用户体验 等方面存在明显不足。如果是公开可访问的静态文件,这种方式可以使用;但如果是需要权限的业务文件,建议改用 blob 流下载方式,更可靠且可控。

(2)解决方案

确保后端接口设置正确的响应头

浏览器是否触发下载,取决于后端返回的 Content-Disposition 响应头。后端必须设置:

bash 复制代码
Content-Disposition: attachment; filename="文件名.xlsx"
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet

attachment 告诉浏览器 "这是一个需要下载的文件",而非直接打开;
filename 指定下载时的默认文件名(支持中文需编码,如 filename*=UTF-8''编码后的文件名)。

前端兼容处理(如果后端已正确设置响应头仍有问题)

如果后端已正确配置,但某些浏览器仍直接打开文件(如浏览器内置了 Excel 预览功能),可以改用动态创建 标签的方式强制触发下载:

javascript 复制代码
/**
 * 下载文件(确保浏览器触发下载)
 */
downloadFile(row) {
    // 1. 校验文件地址是否存在
    if (!row || !row.accessUrl) {
        this.$message.error('文件地址无效,无法下载');
        return;
    }
    
    // 2. 拼接完整下载URL
    const fullUrl = window.location.origin + '/api' + row.accessUrl;
    
    // 3. 动态创建a标签触发下载(替代window.open,更可靠)
    const link = document.createElement('a');
    link.href = fullUrl;
    // 4. 可选:预设置文件名(若后端未返回,可作为默认值)
    // 将文件访问路径(URL)按 / 符号分割成数组,从URL中提取文件名
    const urlParts = row.accessUrl.split('/');
    // 提取最后一段内容作为默认文件名
    const defaultFileName = urlParts[urlParts.length - 1] || '模板文件.xlsx';
    link.download = defaultFileName; // 关键:强制浏览器下载而非打开
    
    // 5. 触发点击并清理
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
}

(3)最后总结

①使用 <a> 标签的 download 属性:

这是核心优化点。download 属性会告诉浏览器:"无论文件类型是什么,都强制触发下载",并可指定默认文件名(优先级低于后端响应头的 filename)。

②兼容性更好:

相比 window.open()<a> 标签方式更不容易被浏览器拦截,且对各种文件类型的下载支持更稳定。

③增加前置校验:

先判断 row.accessUrl 是否存在,避免因空地址导致的错误。