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

如何将文件上传至MySQL并直接显示为可下载文件而非BLOB

问题解答

首先明确:MySQL本身没法直接「显示文件」供下载,你需要调整存储方式和后端逻辑,要么存储文件路径(推荐方案),要么存储文件二进制数据后通过后端转成可下载响应。你的当前代码存在关键问题,下面一步步说明修正方案:

一、两种可行的文件存储方案

1. 存储文件路径(推荐)

  • 将上传文件保存到后端服务器的指定目录(比如uploads/)
  • MySQL仅存储文件的相对路径/唯一文件名,而非文件本身
  • 前端下载时,通过后端静态文件服务或下载接口,根据路径获取文件

2. 存储二进制数据(不推荐大文件)

  • 若一定要存在MySQL中,字段类型需用LONGBLOB(普通BLOB容量不足)
  • 后端需编写接口,将数据库中的二进制数据转换为带正确Content-Type的响应,供前端触发下载

二、代码错误修正

前端(App.js)问题

当前你仅存储了e.target.value,这只是本地文件路径,后端无法获取实际文件内容。需改用FormData上传文件:

import { useState } from 'react';
import Axios from 'axios';

function App() {
  const [employeeName, setName] = useState("");
  const [employeeAge, setAge] = useState("");
  const [employeePosition, setPosition] = useState("");
  const [employeeSalary, setSalary] = useState("");
  const [employeeFile, setFile] = useState(null);

  const submitData = (e) => {
    e.preventDefault(); // 阻止表单默认提交行为
    if (!employeeName || !employeeAge || !employeePosition || !employeeSalary || !employeeFile) {
      alert("请填写所有输入项");
      return;
    }

    const formData = new FormData();
    formData.append('Name', employeeName);
    formData.append('Age', employeeAge);
    formData.append('Position', employeePosition);
    formData.append('Salary', employeeSalary);
    formData.append('file', employeeFile); // 传递实际文件对象

    Axios.post('http://localhost:3001/api/insert', formData, {
      headers: {
        'Content-Type': 'multipart/form-data' // 必须设置该请求头
      }
    }).then(() => {
      alert("上传成功");
      // 重置表单状态
      setName("");
      setAge("");
      setPosition("");
      setSalary("");
      setFile(null);
      document.querySelector('form').reset();
    }).catch(err => {
      console.error(err);
      alert("上传失败");
    });
  }

  return (
    <div className="App">
      <p>CRUD Application</p>
      <div className="formControl">
        <form onSubmit={submitData}>
          <label>Name</label>
          <input type="text" value={employeeName} onChange={(e) => setName(e.target.value)} />
          <label>Age</label>
          <input type="number" value={employeeAge} onChange={(e) => setAge(e.target.value)} />
          <label>Position</label>
          <input type="text" value={employeePosition} onChange={(e) => setPosition(e.target.value)} />
          <label>Salary</label>
          <input type="number" value={employeeSalary} onChange={(e) => setSalary(e.target.value)} />

          <div className='fileUpload'>
            <input type="file" onChange={(e) => setFile(e.target.files[0])} /> {/* 获取文件对象 */}
          </div>

          <button type="submit">Add Data</button>     
          <button type='reset'>Reset</button>
        </form>
      </div>
    </div>
  );
}

export default App;

后端(index.js)问题

需要使用multer中间件处理文件上传,将文件路径存入数据库:
首先安装依赖:

npm install multer

修改后端代码:

const express = require('express');
const cors = require("cors");
const mysql = require('mysql');
const multer = require('multer');
const path = require('path');

const app = express();

// 配置multer:指定文件存储目录和唯一文件名
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, 'uploads/'); // 需提前创建uploads目录,否则会报错
  },
  filename: (req, file, cb) => {
    // 生成唯一文件名,避免重复覆盖
    cb(null, Date.now() + '-' + Math.round(Math.random() * 1E9) + path.extname(file.originalname));
  }
});
const upload = multer({ storage: storage });

const db = mysql.createPool({
  host: "localhost",
  user: "root",
  password: "",
  database: "coba"
});

app.use(cors());
app.use(express.json());
// 提供静态文件服务:允许前端直接访问uploads目录下的文件
app.use('/uploads', express.static(path.join(__dirname, 'uploads')));

// 处理文件上传+数据插入
app.post("/api/insert", upload.single('file'), (req, res) => {
  const Name = req.body.Name;
  const Age = req.body.Age;
  const Position = req.body.Position;
  const Salary = req.body.Salary;
  const filePath = req.file.path; // 获取文件存储的相对路径

  const sqlInsert = "INSERT INTO employee (Name, Age, Position, Salary, Image) VALUES (?,?,?,?,?)";
  db.query(sqlInsert, [Name, Age, Position, Salary, filePath], (err, result) => {
    if (err) {
      console.error(err);
      return res.status(500).json({ message: "数据插入失败" });
    }
    res.status(200).json({ message: "数据插入成功" });
  });
});

// 可选:单独的下载接口(若不想用静态文件服务)
app.get("/api/download/:filename", (req, res) => {
  const filename = req.params.filename;
  const filePath = path.join(__dirname, 'uploads', filename);
  res.download(filePath); // 触发浏览器下载行为
});

app.listen(3001, () => {
  console.log('running on port 3001');
});

三、前端渲染可下载链接

从数据库获取数据后,可直接渲染下载链接:

// 假设已从后端获取dataList数据
{dataList.map(item => (
  <div key={item.id}>
    <p>{item.Name}</p>
    {/* 方案1:用静态文件服务链接 */}
    <a href={`http://localhost:3001/${item.Image}`} target="_blank" download>下载文件</a>
    {/* 方案2:用下载接口 */}
    {/* <a href={`http://localhost:3001/api/download/${path.basename(item.Image)}`} download>下载文件</a> */}
  </div>
))}

内容的提问来源于stack exchange,提问作者RDK

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 16:15:42