咨询:用JavaScript获取近3个月并验证Fastify服务器上传的Excel年月
解决方案:获取近3个月日期范围 + Fastify Excel年月验证
我来帮你搞定这两个问题——先修复你获取近3个月的代码,再给你梳理Fastify服务器上验证Excel的完整流程。
一、修复「获取过去3个月」的函数
你原来的代码有两个核心问题:
- 当当前月份是年初(1月、2月、3月)时,
now.getMonth() - i会出现负数,导致取months数组元素时返回undefined - 只返回了月份名称,但验证需要年份+月份的组合(比如跨年度的情况:2018年1月对应的允许月份是2017年10月、11月、12月)
这里给你两种可选的实现,对应你示例里的两种场景:
场景1:允许当前月+往前推2个月(共3个月,匹配2019年10月允许8月的示例)
// 返回允许的年月集合,格式为 Set<`${number}-${string}`>(如'2019-10'),方便快速验证 const getAllowedYearMonths = () => { const now = new Date(); const allowed = new Set(); for (let i = 0; i < 3; i++) { const targetDate = new Date(now.getFullYear(), now.getMonth() - i, 1); const year = targetDate.getFullYear(); // 月份补零为两位数字,统一格式避免匹配错误 const month = String(targetDate.getMonth() + 1).padStart(2, '0'); allowed.add(`${year}-${month}`); } return allowed; }; // 示例:当前为2019年10月时,集合包含'2019-10'、'2019-09'、'2019-08'
场景2:允许往前推1-3个月(不包含当前月,匹配2018年1月允许10月的示例)
如果你的需求是完全排除当前月,只允许过去的3个完整月份,只需调整循环起始值:
const getAllowedYearMonths = () => { const now = new Date(); const allowed = new Set(); // 从i=1开始,取往前推1-3个月的日期 for (let i = 1; i <= 3; i++) { const targetDate = new Date(now.getFullYear(), now.getMonth() - i, 1); const year = targetDate.getFullYear(); const month = String(targetDate.getMonth() + 1).padStart(2, '0'); allowed.add(`${year}-${month}`); } return allowed; }; // 示例:当前为2018年1月时,集合包含'2017-12'、'2017-11'、'2017-10'
二、Fastify服务器上的Excel验证流程
接下来是在Fastify中处理上传的Excel并验证年月的完整步骤:
1. 安装依赖
先安装处理文件上传和解析Excel的必备库:
npm install @fastify/multipart xlsx
2. Fastify代码实现
const fastify = require('fastify')({ logger: true }); const xlsx = require('xlsx'); const { getAllowedYearMonths } = require('./your-utils-file'); // 导入上面的函数 // 注册文件上传插件 fastify.register(require('@fastify/multipart')); // 处理Excel上传的路由 fastify.post('/upload-excel', async (request, reply) => { try { // 获取上传的文件对象 const file = await request.file(); if (!file) { return reply.status(400).send({ error: '请上传有效的Excel文件' }); } // 读取文件内容为Buffer const buffer = await file.toBuffer(); // 解析Excel工作簿 const workbook = xlsx.read(buffer, { type: 'buffer' }); // 取第一个工作表(假设数据在第一个Sheet中) const worksheet = workbook.Sheets[workbook.SheetNames[0]]; // 转换为JSON格式(假设Excel表头为「年份」「月份」) const excelData = xlsx.utils.sheet_to_json(worksheet, { header: ['年份', '月份'] }); // 获取允许的年月集合 const allowedYearMonths = getAllowedYearMonths(); // 存储验证失败的行信息 const invalidRows = []; // 遍历数据行(跳过第1行表头) for (let i = 1; i < excelData.length; i++) { const row = excelData[i]; const year = row['年份']; const month = row['月份']; // 基础校验:年份和月份必须是数字 if (typeof year !== 'number' || typeof month !== 'number') { invalidRows.push({ row: i + 1, // 对应Excel的实际行号(从1开始) reason: '年份或月份必须为数字格式' }); continue; } // 格式化为统一的'YYYY-MM'字符串 const formattedMonth = String(month).padStart(2, '0'); const yearMonth = `${year}-${formattedMonth}`; // 验证是否在允许范围内 if (!allowedYearMonths.has(yearMonth)) { invalidRows.push({ row: i + 1, reason: `年月${yearMonth}不在允许的近3个月范围内` }); } } // 返回验证结果 if (invalidRows.length > 0) { return reply.status(400).send({ error: '存在不合规的年月数据', invalidRows }); } return reply.send({ message: 'Excel数据验证通过' }); } catch (err) { fastify.log.error('处理Excel上传失败:', err); return reply.status(500).send({ error: '服务器内部处理失败' }); } }); // 启动服务器 const start = async () => { try { await fastify.listen({ port: 3000 }); fastify.log.info(`服务器运行在 http://localhost:${fastify.server.address().port}`); } catch (err) { fastify.log.error('启动服务器失败:', err); process.exit(1); } }; start();
3. 关键细节说明
- 表头适配:如果你的Excel表头不是「年份」「月份」,需要修改
sheet_to_json的header参数,以及后续读取row的字段名。 - 格式统一:把月份转换为两位数字(如5→'05'),避免出现
2024-5和2024-05格式不匹配的问题。 - 错误反馈:返回具体的错误行号和原因,方便用户快速定位并修改Excel内容。
内容的提问来源于stack exchange,提问作者Meet
相关产品推荐
相关产品推荐

