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

使用socket.io+FormData传文件报错:Cannot read property 'transfer-encoding'

问题描述

尝试用socket.io实现图片传输时遇到如下错误:

return req.headers['transfer-encoding'] !== undefined ||
TypeError: Cannot read property 'transfer-encoding' of undefined

此前使用axios+multer时可以正常运行,以下是服务端和客户端代码,请问哪里出错了?

服务端代码

const fileSchema = new mongoose.Schema({
  originalname: String,
  filename: String,
  path: String,
  mimetype: String,
});

const File = mongoose.model("File", fileSchema);
socket.on("ROOM:FILE_UPLOAD", (formData) => {
    upload.single("image")(formData, null, (err) => {
      if (err) console.log(err);
      else {
        const originalname = formData.originalname;
        const filename = formData.filename;
        const path = formData.path;
        const mimetype = formData.mimetype;

        const file = new File({
          originalname,
          filename,
          path,
          mimetype,
        });

        file.save((err, image) => {
          if (err) {
            console.error(err);
          } else {
            console.log(`Image saved to MongoDB: ${image._id}`);
          }
        });
      }
    });
  });

客户端代码

const [file, setFile] = useState(null);
function handleFileSelect(event: any) {
    setFile(event.target.files[0]);
  }
function sendMsg(event) {
    event.preventDefault();
    const formData = new FormData();
    formData.append("image", file);
    socket.emit("ROOM:FILE_UPLOAD", formData);
  }

return (
    <div className="container">
      <div className="row">
        <form encType="multipart/form-data" onSubmit={upload}>
          <input
            type="file"
            accept="image/*"
            onChange={handleFileSelect}
            name="image"
          />
          <button onClick={sendMsg}>send</button>
        </form>
      </div>
    </div>
  );
问题原因

multer是为Express的HTTP请求设计的中间件,它依赖标准的Express req对象(包含headers、body等HTTP请求属性)。但socket.io传输的formData并不是HTTP请求对象,只是普通JavaScript对象,没有headers属性,所以multer执行时会抛出Cannot read property 'transfer-encoding' of undefined错误。

之前用axios+multer正常是因为axios发送的是标准HTTP请求,multer能拿到完整的req对象。

解决方案

放弃用multer处理socket.io的文件传输,直接通过socket.io传输文件二进制数据,服务端手动处理文件保存和数据库存储。

修改后的客户端代码

const [file, setFile] = useState(null);

function handleFileSelect(event: any) {
  setFile(event.target.files[0]);
}

function sendMsg(event) {
  event.preventDefault();
  if (!file) return;

  const reader = new FileReader();
  reader.onload = () => {
    // 发送文件元数据和二进制数据
    socket.emit("ROOM:FILE_UPLOAD", {
      originalname: file.name,
      mimetype: file.type,
      buffer: reader.result // ArrayBuffer格式
    });
  };
  reader.readAsArrayBuffer(file);
}

return (
  <div className="container">
    <div className="row">
      <form onSubmit={sendMsg}>
        <input
          type="file"
          accept="image/*"
          onChange={handleFileSelect}
          name="image"
        />
        <button type="submit">send</button>
      </form>
    </div>
  </div>
);

修改后的服务端代码

const fs = require('fs');
const path = require('path');
const { v4: uuidv4 } = require('uuid'); // 生成唯一文件名

const fileSchema = new mongoose.Schema({
  originalname: String,
  filename: String,
  path: String,
  mimetype: String,
});

const File = mongoose.model("File", fileSchema);

socket.on("ROOM:FILE_UPLOAD", async (fileData) => {
  try {
    // 生成唯一文件名,避免重名
    const filename = `${uuidv4()}_${fileData.originalname}`;
    // 定义文件保存路径(确保uploads目录存在)
    const savePath = path.join(__dirname, 'uploads', filename);
    
    // 将ArrayBuffer转成Buffer并写入文件
    fs.writeFileSync(savePath, Buffer.from(fileData.buffer));

    // 存入MongoDB
    const file = new File({
      originalname: fileData.originalname,
      filename,
      path: savePath,
      mimetype: fileData.mimetype,
    });

    const savedFile = await file.save();
    console.log(`Image saved to MongoDB: ${savedFile._id}`);
  } catch (err) {
    console.error('文件保存失败:', err);
  }
});
额外注意事项
  • 确保服务端的uploads目录存在,否则需要先创建(可以用fs.mkdirSync(path.join(__dirname, 'uploads'), { recursive: true }))。
  • 如果文件较大,建议用socket.io的分片传输,避免单次传输过大数据导致性能问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 14:20:40