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

Docker部署的Next.js中Zip文件上传无存储问题求助

问题描述

在Docker容器中部署的Next.js实例里,需求是通过UI上传Zip文件并存储到容器内的/tmp/compressed/${文件名}路径。调用上传接口后返回200 OK,但目标路径下并未出现存储的文件。已尝试使用multer、formidable以及基于fs的API实现该功能,均未成功。

UI代码(/pages/uploadData.js)
import { useState } from 'react';
import axios from 'axios';
import { useRouter } from 'next/router';
require('dotenv').config();

export default function UploadData() {
  const [selectedFile, setSelectedFile] = useState(null);
  const router = useRouter();

  const handleBack = () => {
    router.push('/');
  };

  const handleFileSelect = (event) => {
    setSelectedFile(event.target.files[0]);
  };

  const handleUpload = async () => {
    if (!selectedFile) {
      alert('Please select a file first.');
      return;
    }

    const formData = new FormData();
    formData.append('file', selectedFile);

    try {
      await axios.post('/api/uploadFolder', formData);
      alert('File uploaded successfully');
    } catch (error) {
      console.error('Error uploading file UPLOAD DATA:', error);
      alert('An error occurred while uploading the file.');
    }
  };

  return (
    <div>
      <h1>Upload Zip File</h1>
      <div>
        <button onClick={handleBack}>Back</button>
      </div>      
      <input type="file" onChange={handleFileSelect} />
      <button onClick={handleUpload} disabled={!selectedFile}>Upload</button>
    </div>
  );
}
原错误接口代码(/pages/api/uploadFolder.js)
import multer from "multer";

const storage = multer.diskStorage({
  destination: "/tmp/compressed",
  filename: (req, file, cb) => {
    cb(null, file.originalname);
  },
});

const upload = multer({ storage });

export default async function handler(req, res) {
  if (req.method === "POST") {
    const uploadedFile = await upload.single("file");
    if (uploadedFile) {
      res.status(200).json({ message: "Archivo cargado correctamente" });
    } else {
      res.status(400).json({ error: "Error al cargar el archivo" });
    }
  } else {
    res.status(405).json({ error: "Método no permitido" });
  }
}
问题分析与修复方案

核心问题

  1. multer调用逻辑错误:upload.single('file')是Express风格的中间件函数,并非异步Promise,直接await不会触发文件上传流程,函数直接返回undefined,导致接口提前返回200但文件未处理。
  2. 目标目录可能不存在:multer不会自动创建destination指定的目录,若/tmp/compressed不存在,上传会静默失败。

修复后的接口代码

import multer from "multer";
import fs from "fs";
import path from "path";

// 确保目标目录存在,不存在则递归创建
const uploadDir = "/tmp/compressed";
if (!fs.existsSync(uploadDir)) {
  fs.mkdirSync(uploadDir, { recursive: true });
}

const storage = multer.diskStorage({
  destination: uploadDir,
  filename: (req, file, cb) => {
    cb(null, file.originalname);
  },
});

const upload = multer({ 
  storage,
  limits: { fileSize: 10 * 1024 * 1024 } // 可根据需求调整文件大小限制,此处为10MB
});

// 将multer中间件包装为Promise,适配Next.js API路由
const uploadSingle = (req, res) => {
  return new Promise((resolve, reject) => {
    upload.single("file")(req, res, (err) => {
      if (err) reject(err);
      resolve(req.file);
    });
  });
};

export default async function handler(req, res) {
  if (req.method === "POST") {
    try {
      const uploadedFile = await uploadSingle(req, res);
      res.status(200).json({ message: "Archivo cargado correctamente", file: uploadedFile });
    } catch (error) {
      console.error("上传错误:", error);
      res.status(400).json({ error: "Error al cargar el archivo", details: error.message });
    }
  } else {
    res.status(405).json({ error: "Método no permitido" });
  }
}

额外检查项

  • Docker目录权限:确认容器内/tmp/compressed目录的读写权限,Next.js进程用户(通常是node)需具备写入权限,可在Dockerfile中添加:
    RUN mkdir -p /tmp/compressed && chown -R node:node /tmp/compressed
    

内容的提问来源于stack exchange,提问作者Daniel Riaño

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 03:56:08