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

NextJS API路由向DjangoREST后端传图片失败问题排查

问题:Next.js API路由转发PATCH请求更新图片失败

我开发了一个NextJS应用,客户端页面请求API路由,再由API路由向Django后端发起PATCH请求更新图片。图片并未成功更新,但直接用Postman/Insomnia调用后端,或客户端直接调用后端时可正常修改。我收到了后端返回的200响应,但图片字段并未实际更新,推测问题出在客户端到API路由的request.body中的文件处理上。

客户端页面代码

const UpdateImageField = async (event: any) => {
    event.preventDefault()

    var formdata = new FormData();
    formdata.append("coverfield", event.target.files[0], event.target.files[0]["name"]);

    const ress = await fetch(`/api/playlist/playlistimage/${playlistediting["id"]}`, {
        method: 'PATCH',
        headers: {
            'Accept': 'application/json',
        },
        body: formdata
    });
}

API路由页面代码

export default async (req, res) => {
    if (req.method === "PATCH") {
        const {
            playlistid
        } = req.query

        const cookies = cookie.parse(req.headers.cookie ?? '');
        const access = cookies.access ?? false;

        if (access === false) {
            return res.status(403).json({
                error: 'User forbidden from making the request'
            });
        }


        try {
            const apiRes = await fetch(`${API_URL}/playlist_api/playlists/${playlistid}/`, {
                method: 'PATCH',
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'multipart/form-data; boundary=---WebKitFormBoundary7MA4YWxkTrZu0gW',
                    'Authorization': `Bearer ${access}`
                },
                body: req.body
            });

            const data = await apiRes.json();
            console.log(data)

            if (apiRes.status === 200) {
                return res.status(200).json({
                    updatedplaylist: data
                });
            } else {
                return res.status(apiRes.status).json({
                    error: data.error
                });
            }
        } catch (err) {
            return res.status(500).json({
                error: 'Something went wrong when changing the image'
            });
        }
    }
}

问题分析与解决方案

问题核心是Next.js默认的请求体解析器不支持multipart/form-data类型,直接传递req.body会导致文件数据丢失,后端收到空表单数据,因此返回200但未实际更新图片。

解决步骤

  1. 安装表单解析依赖
    在项目中安装formidable来处理文件表单:
npm install formidable
# 或
yarn add formidable
  1. 修改API路由代码
    禁用Next.js默认的body解析器,用formidable解析请求体后重新构建FormData再转发:
import formidable from 'formidable';
import cookie from 'cookie';

// 禁用Next.js默认的body解析器
export const config = {
  api: {
    bodyParser: false,
  },
};

export default async (req, res) => {
  if (req.method === "PATCH") {
    const { playlistid } = req.query;
    const cookies = cookie.parse(req.headers.cookie ?? '');
    const access = cookies.access ?? false;

    if (access === false) {
      return res.status(403).json({ error: 'User forbidden from making the request' });
    }

    // 解析multipart/form-data请求体
    const form = formidable({ multiples: false });
    const [fields, files] = await form.parse(req);

    // 重新构建FormData
    const formData = new FormData();
    if (files.coverfield) {
      const file = files.coverfield[0];
      formData.append('coverfield', file, file.originalFilename);
    }

    try {
      const apiRes = await fetch(`${process.env.API_URL}/playlist_api/playlists/${playlistid}/`, {
        method: 'PATCH',
        headers: {
          'Authorization': `Bearer ${access}`,
          // 不要手动设置Content-Type,浏览器会自动生成带正确boundary的头部
        },
        body: formData,
      });

      const data = await apiRes.json();
      console.log(data);

      if (apiRes.status === 200) {
        return res.status(200).json({ updatedplaylist: data });
      } else {
        return res.status(apiRes.status).json({ error: data.error });
      }
    } catch (err) {
      return res.status(500).json({ error: 'Something went wrong when changing the image' });
    }
  } else {
    res.setHeader('Allow', ['PATCH']);
    res.status(405).end(`Method ${req.method} Not Allowed`);
  }
};
  1. 关键注意事项
  • 必须禁用Next.js默认的bodyParser,否则无法正确解析文件表单;
  • 转发请求时不要手动设置Content-Type,手动设置会导致boundary不匹配,后端无法解析;
  • formidable返回的fields和files均为数组类型,需取第一个元素使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 01:24:30