You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js应用中如何将PDF等文件以二进制形式存储到SQL Server

解决Next.js上传文档到SQL Server并存储为VARBINARY(MAX)的问题

问题诊断

你当前的实现存在两个核心问题:

  1. 二进制数据损坏:使用file.text()将PDF/DOCX这类二进制文档转为文本,会因编码解析破坏原始数据结构,导致无法正确还原文件。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 11:23:22