如何基于Express+Node.js实现单文件选择下载功能?
实现单个文件下载功能方案
前端修改
- 给每个文件添加独立下载按钮,传递当前文件名到下载函数
- 实现单文件下载逻辑,处理文件流的浏览器下载触发
修改后的前端代码:
import axios from "axios"; import { useEffect, useState } from "react"; import { useParams } from "react-router-dom"; import './DisplayPage.css'; import NavBar from "../NavBar/NavBar"; export default function SingleDoc(){ const{id} = useParams(); const[place,setPlace] = useState(null); useEffect(()=>{ if(!id){ return; } axios.get(`/staff/${id}`).then(response =>{ setPlace(response.data); }) },[id]); if(!place) return ''; // 单个文件下载函数 async function downloadSingleFile(filename) { try { // 请求后端获取文件流,指定响应类型为blob const response = await axios.get(`/single-download`, { params: { id, filename }, responseType: 'blob' }); // 创建临时下载链接触发浏览器下载 const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement('a'); link.href = url; link.setAttribute('download', filename); document.body.appendChild(link); link.click(); // 清理临时资源 link.remove(); window.URL.revokeObjectURL(url); } catch (error) { console.error('下载失败:', error); } }; // 原有批量下载函数(优化下载逻辑) async function downloadButton(ev){ ev.preventDefault(); try { const response = await axios.get(`/download/${id}`, { responseType: 'blob' }); const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement('a'); link.href = url; link.setAttribute('download', `${id}_files.zip`); document.body.appendChild(link); link.click(); link.remove(); window.URL.revokeObjectURL(url); } catch (error) { console.error('批量下载失败:', error); } }; return( <div> <NavBar/> <div className="single-doc"> {place.profile.length > 0 && place.profile.map(photo => ( <div key={photo}> <div> <img className="file-pics" src={`http://localhost:4000/uploads/${photo}`} alt='' /> {photo} {/* 新增单个文件下载按钮 */} <button onClick={() => downloadSingleFile(photo)} style={{marginLeft: '10px'}}>下载此文件</button> </div> </div> ))} <div> <button onClick={downloadButton}> 下载全部文件</button> </div> </div> </div> ) }
后端修改
完善/single-download接口,通过staff ID和文件名获取对应文件,同时添加权限验证避免非法访问:
app.get("/single-download", async (req, res) => { try { const { id, filename } = req.query; // 获取对应staff文档 const staffDoc = await Staff.findById(id); if (!staffDoc) { return res.status(404).send("Staff不存在"); } // 验证文件名是否属于该staff的文件列表,防止路径遍历攻击 if (!staffDoc.profile.includes(filename)) { return res.status(403).send("无权限下载该文件"); } // 构建文件路径 const filePath = `${__dirname}/uploads/${filename}`; // 返回文件供浏览器下载 res.download(filePath, filename, (err) => { if (err) { res.status(500).send("文件下载失败"); } }); } catch (error) { console.error(error); res.status(500).send("服务器错误"); } });
关键说明
- 前端通过
responseType: 'blob'接收二进制文件流,再通过临时链接触发浏览器下载 - 后端增加文件权限校验,确保用户只能下载对应staff名下的文件,避免安全风险
- 保留原有批量下载功能,同时新增单文件下载选项
内容的提问来源于stack exchange,提问作者Caleb Bako
相关产品推荐
相关产品推荐

