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

使用Node.js Express构建Firebase Storage图片上传API时出现JSON解析错误的问题求助

Fixing "SyntaxError: Unexpected token � in JSON at position 0" When Uploading Files to Firebase Storage via Express API

Hey there, let's break down exactly why you're hitting this error and walk through how to fix it properly.

What's Causing the Error?

You've got two critical mismatches in your code right now:

  1. Client-side Content-Type mismatch: You're sending a raw File object as the request body but setting Content-Type: application/json. Files are binary data, not JSON, so Express's express.json() middleware tries (and fails) to parse that binary data as valid JSON—hence the weird token error.
  2. Server-side missing multipart handling: File uploads require the multipart/form-data content type, but your server doesn't have any middleware configured to handle this format.

Step-by-Step Fixes

1. Update the Client Code

You need to wrap your file in a FormData object (the standard way to send files over HTTP) and let the browser handle the content type automatically:

const postImage = async (image) => {
  console.log(image);
  const formData = new FormData();
  // Add the file to FormData—"uploadedImage" is the field name we'll use on the server
  formData.append('uploadedImage', image);

  const response = await fetch("http://localhost:8000/postImage", {
    method: "POST",
    body: formData
    // DO NOT set Content-Type here! The browser will auto-add the correct multipart/form-data header
  });
  
  console.log(await response.json());
};

2. Configure the Server for File Uploads

We'll use multer—the most popular Express middleware for handling multipart/form-data—to process the file, then upload it directly to Firebase Storage.

Install Multer

First, install the package in your project:

npm install multer

Update Your Express Server File

Modify your main server file to initialize multer and pass it to your routes:

const express = require("express");
const morgan = require("morgan");
const cors = require('cors');
const multer = require('multer'); // Import multer
const app = express();

// Settings
app.set('port', process.env.PORT || 8000);
app.set('json spaces', 4);

// Middleware
app.use(morgan("dev"));
// Keep these for JSON/urlencoded requests—they won't interfere with file upload routes
app.use(express.json({limit: "1000mb"}));
app.use(express.urlencoded({extended: true}));
app.use(cors({origin: "http://localhost:3000"}));

// Configure multer to store files in memory (easy to pipe to Firebase)
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });

// Pass the multer instance to your routes
app.use(require("./routes/index")(upload));

app.listen(app.get('port'), () => {
  console.log("Server using port " + app.get('port'));
});

Update Your Route to Handle Firebase Upload

First, make sure you've set up the Firebase Admin SDK (download your service account key from the Firebase Console and place it in your project). Then modify your route:

const { Router } = require('express');
const admin = require('firebase-admin');
const router = Router();

// Initialize Firebase Admin (do this once—you could also move this to your main server file)
const serviceAccount = require('../path/to/your/serviceAccountKey.json');
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  storageBucket: 'your-bucket-name.appspot.com' // Replace with your Firebase Storage bucket name
});
const bucket = admin.storage().bucket();

// Export the router with access to the multer upload instance
module.exports = (upload) => {
  // Use upload.single('uploadedImage') to handle a single file with the field name we set on the client
  router.post('/postImage', upload.single('uploadedImage'), async (req, res) => {
    try {
      console.log("Received file:", req.file); // Now this code will run!

      // Check if a file was actually uploaded
      if (!req.file) {
        return res.status(400).json({ message: "No file provided" });
      }

      // Set up the Firebase Storage file path/name
      const fileName = `uploads/${Date.now()}_${req.file.originalname}`;
      const file = bucket.file(fileName);

      // Create a write stream to upload the file buffer to Firebase
      const stream = file.createWriteStream({
        metadata: {
          contentType: req.file.mimetype // Preserve the original file type
        }
      });

      // Handle stream errors
      stream.on('error', (err) => {
        console.error(err);
        return res.status(500).json({ error: "Failed to upload file to Firebase" });
      });

      // When upload finishes, return the public URL (if needed)
      stream.on('finish', async () => {
        // Make the file public (optional—skip if you want private files)
        await file.makePublic();
        const publicUrl = `https://storage.googleapis.com/${bucket.name}/${file.name}`;

        return res.status(200).json({
          message: "File uploaded successfully!",
          fileUrl: publicUrl
        });
      });

      // Write the file buffer to the stream
      stream.end(req.file.buffer);

    } catch (error) {
      console.log(error);
      return res.status(500).json({ error: error.message });
    }
  });

  return router;
};

Key Notes to Remember

  • Never manually set Content-Type for FormData: The browser automatically adds the correct multipart/form-data header with a boundary value—setting it manually will break parsing.
  • Multer storage options: We used memoryStorage() for simplicity, which works well for small files. For large files, use diskStorage() to temporarily save files to your server, then upload to Firebase (just remember to clean up temp files afterward).
  • Firebase permissions: Ensure your service account has the correct Storage permissions (check the Firebase Console's IAM section if uploads fail due to permissions).

内容的提问来源于stack exchange,提问作者Jorge Sánchez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 02:47:50