标题:解决嵌套 Fetch 请求中第二个 API 接收空请求体的问题

本文详解如何在前端使用嵌套 `fetch`(如先上传图片再创建用户档案)时,正确设置请求头(尤其是 `content-type`),避免后端 `req.body` 为空的常见错误。

在前后端分离开发中,一个典型场景是:先通过 multipart/form-data 上传文件获取 ID,再用该 ID 和其他字段(如 name)调用另一接口创建资源。你遇到的 createProfile 接口始终收到 undefined 的 req.body.name,根本原因在于:第二个 fetch 请求未声明 Content-Type: application/json,导致 Express 默认无法解析 JSON 请求体

? 问题定位:缺失关键请求头

你的第一个请求(上传图片)使用 FormData,浏览器会自动设置 Content-Type: multipart/form-data; boundary=...,Express 配合 multer 或类似中间件可正常解析。

但第二个请求:

fetch('http://localhost:4000/api/createProfile', {
  method: 'POST',
  body: JSON.stringify({ name: name.value, imageid: resData.imageid })
})

⚠️ 此处 body 是字符串,但未显式设置 headers: { "Content-Type": "application/json" }
结果:Express 的 body-parser.json() 中间件因检测不到合法 Content-Type 头,直接跳过解析,req.body 保持为空对象 {} —— 这正是你 console.log(requestedData.name) 输出 undefined 的根源。

✅ 正确写法:显式声明 JSON Content-Type

修改你的 JS 代码,为第二个 fetch 添加请求头:

const resProfile = await fetch('http://localhost:4000/api/createProfile', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json' // ← 关键!必须添加
  },
  body: JSON.stringify({
    name: name.value,
    imageid: resData.imageid
  })
});

同时,请确保后端 Express 已正确配置 body-parser(推荐使用内置中间件):

// server.js(Express 4.16.0+)
app.use(express.json());        // 解析 application/json
app.use(express.urlencoded({ extended: true })); // 解析 application/x-www-form-urlencoded
// 注意:上传文件需额外使用 multer(非 body-parser)
? 提示:express.json() 不会处理 multipart/form-data,所以上传接口仍需 multer;但 createProfile 是纯 JSON 请求,express.json() 完全适用。

? 完整修复后的前端逻辑(含错误处理)

const form = document.getElementById('createProfile');
const nameInput = document.getElementById('name');

form.addEventListener('submit', async (e) => {
  e.preventDefault();
  const formData = new FormData(form);

  try {
    // Step 1: 上传图片
    const uploadRes = await fetch('http://localhost:4000/api/uploadimage', {
      method: 'POST',
      body: formData
    });

    if (!uploadRes.ok) throw new Error(`Upload failed: ${uploadRes.status}`);

    const uploadData = await uploadRes.json();
    if (uploadData.code !== 200) throw new Error(uploadData.success || 'Upload error');

    // Step 2: 创建档案(关键:设置 Content-Type)
    const profileRes = await fetch('http://localhost:4000/api/createProfile', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        name: nameInput.value.trim(),
        imageid: uploadData.imageid
      })
    });

    if (!profileRes.ok) throw new Error(`Create failed: ${profileRes.status}`);

    const profileData = await profileRes.json();
    console.log(`${profileData.profileid} has been created`);

  } catch (err) {
    console.error('Error:', err.message);
    alert(`操作失败:${err.message}`);
  }
});

⚠️ 其他注意事项

  • 不要混用 FormData 和 JSON.stringify:FormData 用于文件上传;纯 JSON 数据请用 JSON.stringify + Content-Type: application/json。
  • 服务端日志验证:在 createProfile 路由开头加 console.log('Raw body:', JSON.stringify(req.body)); 确认是否已解析。
  • CORS 配置:若跨域,确保后端 cors() 允许 Content-Type 头:
    app.use(cors({
      allowedHeaders: ['Content-Type', 'Authorization']
    }));
  • 表单优化建议:将 改为

遵循以上修正,你的嵌套请求即可稳定传递数据——核心就一句话:发送 JSON,必设 Content-Type: application/json