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

Node.js管理后台如何向Firebase已有的Articles集合按指定结构上传图片

实现方案

前置准备

首先安装Firebase Admin SDK用于操作Firestore数据库:

npm install firebase-admin

在你的../config/目录下新增Firebase Admin初始化配置,示例如下:

// ../config/firebaseAdmin.js
const admin = require('firebase-admin');
// 从Firebase控制台下载服务账号密钥JSON文件导入即可
const serviceAccount = require('./你的服务账号密钥文件名.json');

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  storageBucket: '你的Bucket名称' // 和你之前使用的bucketname保持一致
});

const db = admin.firestore();
module.exports = { admin, db };

调整说明

你需要同时完成两项核心调整才能匹配现有结构:

  • 调整Cloud Storage的文件存储路径,匹配要求的层级结构
  • 图片上传成功后,往Firestore的对应子集合写入图片记录,供Flutter端的StreamBuilder监听读取

完整修改后代码

const express = require('express')
const bodyParser = require('body-parser')
const multer = require('multer')
const util = require('util')
const gc = require('../config/')
const bucket = gc.bucket(bucketname)
// 引入刚才配置的Firestore实例
const { db } = require('../config/firebaseAdmin')

const app = express()

const multerMid = multer({
  storage: multer.memoryStorage(),
  limits: {
    fileSize: 5 * 1024 * 1024,
  },
});

app.disable('x-powered-by')
app.use(multerMid.single('file'))
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: false}))

const { format } = util

// 给uploadImage方法新增postId参数
const uploadImage = (file, postId) => new Promise((resolve, reject) => {
  const { originalname, buffer } = file
  // 调整文件存储路径为 articles/{postId}/images/文件名
  const fileName = originalname.replace(/ /g, "_")
  const blob = bucket.file(`articles/${postId}/images/${fileName}`)
  const blobStream = blob.createWriteStream({
    resumable: false
  })

  blobStream.on('finish', () => {
    const publicUrl = format(
      `https://storage.googleapis.com/${bucket.name}/${blob.name}`
    )
    resolve(publicUrl)
  })
  .on('error', () => {
    reject(`Unable to upload image, something went wrong`)
  })
  .end(buffer)
})

app.post('/uploads', async (req, res, next) => {
  try {
    const myFile = req.file
    // 从请求的formData中获取对应帖子的postId
    const postId = req.body.postId
    if (!postId) {
      return res.status(400).json({message: '缺少postId参数'})
    }
    const imageUrl = await uploadImage(myFile, postId)
    // 上传成功后往Firestore对应子集合写入记录
    await db.collection('articles').doc(postId).collection('images').add({
      url: imageUrl,
      createdAt: new Date(),
      // 可按需补充其他字段,比如文件名、文件大小等
      fileName: myFile.originalname
    })

    res
      .status(200)
      .json({
        message: "Upload was successful",
        data: imageUrl
      })
  } catch (error) {
    next(error)
  }
})

app.use((err, req, res, next) => {
  res.status(500).json({
    error: err,
    message: 'Internal server error!',
  })
  next()
})

app.listen(9001, () => {
  console.log('app now listening for requests!!!')
})

前端调用要求

管理后台调用上传接口时,使用FormData格式传递参数,除了file字段外,额外增加postId字段传入对应帖子的ID即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 03:24:01