如何用Node.js/Express实现带有效期的下载链接(含前后端代码)
Node.js + Express 限时失效下载链接实现方案
实现逻辑
通过JWT(JSON Web Token)生成带过期时间的签名下载链接,请求下载时校验签名有效性和过期状态,无需额外存储数据即可实现链接限时生效,适合小型项目快速落地。
依赖安装
首先在项目根目录执行以下命令安装所需依赖:
npm install express jsonwebtoken cors
后端完整代码
const express = require('express'); const jwt = require('jsonwebtoken'); const path = require('path'); const cors = require('cors'); const fs = require('fs'); const app = express(); // 前后端分离场景下配置跨域 app.use(cors()); // 解析POST请求的JSON参数 app.use(express.json()); // 签名密钥 *生产环境请务必存储在环境变量中,禁止硬编码泄露* const SECRET_KEY = 'replace_this_with_your_own_secret_key'; // 可下载文件存放目录,需提前在项目根目录创建该文件夹 const DOWNLOAD_DIR = path.join(__dirname, 'download-files'); // 生成限时下载链接接口 app.post('/generate-download-link', (req, res) => { const { fileName, expireSeconds = 3600 } = req.body; // 校验文件是否存在,过滤无效请求 const targetFilePath = path.join(DOWNLOAD_DIR, fileName); if (!fs.existsSync(targetFilePath)) { return res.status(404).json({ msg: '请求的文件不存在' }); } // 校验文件名合法性,防止路径遍历漏洞 if (fileName.includes('..') || path.resolve(targetFilePath) !== path.join(DOWNLOAD_DIR, path.basename(fileName))) { return res.status(403).json({ msg: '非法的文件名' }); } // 生成带过期时间的签名token const downloadToken = jwt.sign( { fileName }, SECRET_KEY, { expiresIn: expireSeconds } ); // 拼接完整下载链接返回 const downloadLink = `${req.protocol}://${req.get('host')}/download?token=${downloadToken}`; res.json({ downloadLink, expireTime: new Date(Date.now() + expireSeconds * 1000).toLocaleString() }); }); // 下载处理接口 app.get('/download', (req, res) => { const { token } = req.query; if (!token) { return res.status(400).send('无效的下载链接'); } try { // 校验token有效性,过期/签名错误都会抛出异常 const decoded = jwt.verify(token, SECRET_KEY); const targetFilePath = path.join(DOWNLOAD_DIR, decoded.fileName); // 二次校验文件存在 if (!fs.existsSync(targetFilePath)) { return res.status(404).send('文件不存在'); } // 触发文件下载 res.download(targetFilePath, decoded.fileName); } catch (err) { if (err.name === 'TokenExpiredError') { return res.status(410).send('该下载链接已过期'); } res.status(403).send('无效的下载链接'); } }); // 启动服务 const PORT = 3000; app.listen(PORT, () => { console.log(`服务已启动,访问地址:http://localhost:${PORT}`); });
前端示例代码(原生HTML+JS,无框架依赖)
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>限时下载链接生成工具</title> </head> <body> <div style="margin: 20px;"> <div style="margin-bottom: 10px;"> <label>文件名:</label> <input type="text" id="fileNameInput" value="test.pdf" placeholder="请输入要下载的文件名"> </div> <div style="margin-bottom: 10px;"> <label>链接有效期(秒):</label> <input type="number" id="expireInput" value="60" min="10"> </div> <button id="generateBtn">生成下载链接</button> <div id="resultContainer" style="margin-top: 20px;"></div> </div> <script> const generateBtn = document.getElementById('generateBtn'); const resultContainer = document.getElementById('resultContainer'); generateBtn.addEventListener('click', async () => { const fileName = document.getElementById('fileNameInput').value.trim(); const expireSeconds = Number(document.getElementById('expireInput').value); if (!fileName) { resultContainer.innerHTML = '<p style="color: red;">请输入文件名</p>'; return; } try { const resp = await fetch('http://localhost:3000/generate-download-link', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ fileName, expireSeconds }) }); const data = await resp.json(); if (resp.ok) { resultContainer.innerHTML = ` <p>✅ 下载链接生成成功,有效期至:${data.expireTime}</p> <a href="${data.downloadLink}" target="_blank">点击直接下载</a> <p style="word-break: break-all; margin-top: 10px;">链接地址:${data.downloadLink}</p> `; } else { resultContainer.innerHTML = `<p style="color: red;">❌ 生成失败:${data.msg}</p>`; } } catch (e) { resultContainer.innerHTML = '<p style="color: red;">❌ 请求失败,请检查后端服务是否正常启动</p>'; } }); </script> </body> </html>
使用步骤
- 在项目根目录创建
download-files文件夹,将需要提供下载的文件放到该目录下 - 运行后端服务:
node server.js(假设后端代码保存为server.js) - 直接打开前端HTML文件,输入对应的文件名和有效期,点击生成链接即可测试
注意事项
- 生成链接的有效期最长不要超过7天,避免链接泄露后被长期滥用
- 生产环境建议添加接口请求频率限制,防止接口被恶意刷量
- 如果需要支持手动撤销下载链接,可以将生成的token、过期时间、状态存储到数据库,下载时额外校验token是否已被禁用
内容的提问来源于stack exchange,提问作者DEADPOOL
相关产品推荐
相关产品推荐

