在现代 web 开发中,文件下载功能是一个常见且重要的需求。在前端实现获取后端返回的文件流并下载的过程,主要涉及到调用后端 API、处理响应数据以及触发下载。这篇文章将详细介绍如何实现这个功能,并附上一些代码示例。

1. 背景知识

通常,后端 API 会返回文件流(如 PDF、Excel 等),前端需要将这个流进行处理,并提供给用户下载。浏览器处理下载的方式通常是通过创建一个 <a> 标签并模拟点击,或者使用 Blob 对象和 URL API。

2. 示例场景

假设我们有一个后端接口 GET /download,用来下载某个报告文件。前端使用 Fetch API 请求这个接口。

3. 前端实现步骤

步骤 1: 发起请求

我们可以使用 Fetch API 获取文件流。需要注意的是,为了确保返回的是一个文件流,我们需要指定返回的内容类型。

async function downloadFile() {
    try {
        const response = await fetch('/download', {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json'
            }
        });

        if (!response.ok) {
            throw new Error('网络响应失败');
        }

        // 返回的内容处理为 blob
        const blob = await response.blob();
        const fileName = getFileName(response); // 从响应中获取文件名

        // 执行下载
        triggerDownload(blob, fileName);
    } catch (error) {
        console.error('下载过程中发生错误:', error);
    }
}

步骤 2: 获取文件名

获取文件名可以通过后端返回的 Content-Disposition 头部来实现。为了简化,我们可以创建一个函数来提取文件名:

function getFileName(response) {
    const disposition = response.headers.get('Content-Disposition');
    if (disposition && disposition.indexOf('attachment') !== -1) {
        const matches = /filename[^;=\n]*=((['"]).+?\2|([^;\n]*))/i.exec(disposition);
        if (matches != null && matches[1]) {
            return matches[1].replace(/['"]/g, '');
        }
    }
    return 'downloaded_file'; // 默认文件名
}

步骤 3: 触发下载

接下来,我们需要将 Blob 对象转换为一个 URL,并触发下载:

function triggerDownload(blob, fileName) {
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = fileName;
    document.body.appendChild(a);
    a.click();

    // 清理 DOM 元素和 URL 对象
    a.remove();
    window.URL.revokeObjectURL(url);
}

4. 完整代码示例

将上述所有代码整合在一起,形成一个完整的下载功能:

async function downloadFile() {
    try {
        const response = await fetch('/download', {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json'
            }
        });

        if (!response.ok) {
            throw new Error('网络响应失败');
        }

        const blob = await response.blob();
        const fileName = getFileName(response);
        triggerDownload(blob, fileName);
    } catch (error) {
        console.error('下载过程中发生错误:', error);
    }
}

function getFileName(response) {
    const disposition = response.headers.get('Content-Disposition');
    if (disposition && disposition.indexOf('attachment') !== -1) {
        const matches = /filename[^;=\n]*=((['"]).+?\2|([^;\n]*))/i.exec(disposition);
        if (matches != null && matches[1]) {
            return matches[1].replace(/['"]/g, '');
        }
    }
    return 'downloaded_file'; // 默认文件名
}

function triggerDownload(blob, fileName) {
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = fileName;
    document.body.appendChild(a);
    a.click();

    a.remove();
    window.URL.revokeObjectURL(url);
}

5. 总结

通过以上步骤,我们实现了一个简单的文件下载功能。前端通过 Fetch API 获取后端返回的文件流,提取文件名并使用 Blob 触发下载。这种方式有效地处理了用户的下载请求,确保了其流畅性和用户体验。希望这篇文章对你在前端文件下载的实现上有所帮助!

点赞(0) 打赏

微信小程序

微信扫一扫体验

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部