Next.js应用中如何将PDF等文件以二进制形式存储到SQL Server
解决Next.js上传文档到SQL Server并存储为VARBINARY(MAX)的问题
问题诊断
你当前的实现存在两个核心问题:
- 二进制数据损坏:使用
file.text()将PDF/DOCX这类二进制文档转为文本,会因编码解析破坏原始数据结构,导致无法正确还原文件。 - SQL注入风险与语法错误:直接将前端传入的数据拼接进SQL语句,不仅有严重注入风险,
CAST也无法处理已损坏的文本数据,必然执行失败。
可行解决方案
前端代码修改
改用FormData传递文件,这是处理文件上传的标准方式,能完整保留二进制数据:
async function filesUpload(e) { e.preventDefault(); const file = e.target.file.files[0]; // 多类型文件验证 const allowedTypes = [ 'application/pdf', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ]; if (!allowedTypes.includes(file.type)) { alert("请选择PDF或DOCX格式的文档"); return; } const formData = new FormData(); formData.append('document', file); // 附加业务所需字段(示例值根据实际场景调整) formData.append('contractId', 302); formData.append('userId', 1); formData.append('docName', 'adad'); const endpoint = '/api/PostData/insertContractDoc'; const options = { method: 'POST', body: formData // 无需手动设置Content-Type,浏览器会自动处理 }; try { const response = await fetch(endpoint, options); const result = await response.json(); console.log('上传成功:', result); } catch (err) { console.error('上传失败:', err); alert('文件上传失败,请重试'); } }
API端点代码修改
使用mssql的参数化查询处理二进制数据,彻底避免注入风险,同时正确插入VARBINARY(MAX)类型字段:
const sql = require('mssql'); const multer = require('multer'); const configOBJ = require('../../../components/configSQL.js'); // 配置multer将文件存储到内存,直接获取Buffer const upload = multer({ storage: multer.memoryStorage() }); // 禁用Next.js默认的bodyParser,让multer处理FormData export const config = { api: { bodyParser: false, }, }; async function insertContractDoc(req, res) { if (req.method !== 'POST') { return res.status(405).json({ message: '仅支持POST请求' }); } try { // 从FormData中获取字段与文件 const { contractId, userId, docName } = req.body; const document = req.file; if (!document) { return res.status(400).json({ message: '未上传文件' }); } await sql.connect(configOBJ.confSQL); // 参数化查询,安全插入二进制数据 const result = await sql.request() .input('contractId', sql.Int, contractId) .input('userId', sql.Int, userId) .input('docName', sql.NVarChar, docName) .input('documentData', sql.VarBinary, document.buffer) .query(` INSERT INTO [CONTRACTDOCUMENTS] (ContractId, UserId, DocName, DocumentData) VALUES (@contractId, @userId, @docName, @documentData) `); return res.status(200).json({ message: '文件存储成功', result }); } catch (err) { console.error('数据库操作失败:', err); return res.status(500).json({ message: '服务器内部错误', error: err.message }); } finally { await sql.close(); } } // 挂载multer中间件,处理名为document的文件字段 export default upload.single('document')(insertContractDoc);
关键注意事项
- 依赖安装:Next.js API默认不解析
multipart/form-data,需安装multer处理文件上传:npm install multer - 表结构匹配:确保
CONTRACTDOCUMENTS表的字段与插入语句对应,示例中省略了null对应的字段,需根据实际表结构调整。 - 双向验证:前端和后端都要做文件类型校验,避免恶意文件上传。
内容的提问来源于stack exchange,提问作者Martin Lauf
相关产品推荐
相关产品推荐

