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

Node.js+MongoDB GridFS文件上传后下载删除功能实现问题

MongoDB GridFS 文件下载/删除功能实现

现有代码说明

我已在本地服务通过server.js实现MongoDB文件上传功能,server.js现有代码如下:

// 已替换个人ID和密码
const mongoURI = "mongodb+srv://myID:myPW@cluster0.0ct4j.mongodb.net/test";

// Mongo连接
const conn = mongoose.createConnection(mongoURI);

// 初始化gfs
let gfs;

conn.once('open', () =>{
    gfs = Grid(conn.db, mongoose.mongo);
    // GridFsStorage默认使用fs作为集合名,这里需要对齐配置
    gfs.collection('fs');
});

// 中间件
server.use(bodyParser.json()); 
server.use(methodOverride('_method'));  

// GridFS存储配置
const storage = new GridFsStorage({
  url: mongoURI,
  cache: true,
  file: (req, file) => {
    return file.originalname + Date.now();
  }
});

const upload = multer({ storage });

server.get("/upload", (req,res) =>{
    res.render('upload');
});

// 文件上传接口
server.post('/upload', upload.single('file'), (req, res) => {
  res.redirect("/");
});

对应upload.ejs上传页面代码如下:

<form action="/upload" method = "post" enctype="multipart/form-data"> 
    <div class="custom-file mb-3">
        <input type="file" name="file" id="file" class="custom-file-input">
    </div>
    <input type="submit" value="Submit" class="btn btn-primary btn-block">
</form>

目前访问localhost:3000/list可正常查看已上传文件列表,list.ejs现有代码如下:

<% if(files){ %>
  <% files.forEach(function(file) { %>
    <div class="card card-body mb-3">
      <%= file.filename %>
      <a href= <%=mongoURI%> download=file>Download</a>
            <form action= "<%= file._id %>?_method=DELETE" method="get"> 
              <button class="delete">DELETE</button>
            </form>
            <form action="<%= file._id %>?_method=DOWNLOAD" method="get">
              <button class="download">DOWNLOAD</button>
            </form>

    </div>
    <% }) %>
      <% } else { %>
        <p>No files to show</p>
        <% } %>

当前list.ejs可正确读取文件名,需要实现文件下载与删除功能。由于前端不能直接与数据库交互,相关逻辑需要在server.js中编写,参考上传逻辑开发未成功。


问题修复与功能实现

原有代码问题点

  • 重复声明了Mongo连接变量conn,GridFS初始化时未指定和存储引擎对齐的集合名
  • 列表页下载链接直接填写MongoDB连接地址无法生效,删除/下载请求路径不完整
  • methodOverride默认仅拦截POST请求,现有删除表单用GET方法无法触发DELETE方法的路由

第一步:在server.js中补充下载、删除接口

在现有上传接口后追加以下代码:

// 文件列表接口(已实现可忽略,注意要将查询到的文件列表传入模板)
server.get('/list', (req, res) => {
  gfs.files.find().toArray((err, files) => {
    if(!files || files.length === 0) return res.render('list', {files: false});
    return res.render('list', {files: files});
  })
})

// 文件下载接口
server.get('/files/:id/download', (req, res) => {
  gfs.files.findOne({_id: mongoose.Types.ObjectId(req.params.id)}, (err, file) => {
    if(!file || file.length === 0) return res.status(404).send('文件不存在');
    // 设置响应头,触发浏览器下载行为
    res.set('Content-Type', file.contentType);
    res.set('Content-Disposition', `attachment; filename="${file.filename}"`);
    // 读取GridFS文件流写入响应
    const readStream = gfs.createReadStream(file.filename);
    readStream.pipe(res);
  })
})

// 文件删除接口
server.delete('/files/:id', (req, res) => {
  gfs.remove({_id: mongoose.Types.ObjectId(req.params.id), root: 'fs'}, (err, gridStore) => {
    if(err) return res.status(404).send('删除失败');
    res.redirect('/list');
  })
})

第二步:修改list.ejs模板的请求地址

把原有卡片内的下载、删除按钮部分替换为以下代码:

<div class="card card-body mb-3">
  <%= file.filename %>
  <a href="/files/<%= file._id %>/download" class="btn btn-success">下载文件</a>
  <form action="/files/<%= file._id %>?_method=DELETE" method="post"> 
    <button class="btn btn-danger delete" type="submit">删除文件</button>
  </form>
</div>

注意:删除表单必须用post方法,否则methodOverride不会识别_method参数指定的DELETE请求


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 21:42:12