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

axios发送PUT请求时同时上传图片与文本的正确方法

问题根源

你遇到的字段不更新、上传失败问题,来自三个实现错误:

  • 发送multipart/form-data类型请求时,不能直接传递普通JavaScript对象作为请求体,必须使用FormData实例封装所有文本、文件字段
  • 手动设置Content-Type: multipart/form-data会丢失请求必须的boundary边界分隔符,服务端无法正确拆分解析请求内容,这个头应该交给浏览器/axios自动生成,禁止手动配置
  • 表单配置和事件绑定有冗余错误:enctype="form.data"是无效值,同时表单submit事件绑定了不存在的方法、提交按钮又重复绑定点击事件,可能导致重复触发请求。
正确实现方案

1. 修改请求逻辑

所有需要和文件一起提交的字段,全部装入FormData实例,请求时不要手动设置Content-Type头,修改后的脚本代码如下:

<script setup>
import { ref } from "vue";
import { useRouter } from "vue-router";
import http from "../http-common";

const router = useRouter();
// 绑定文件选择input的ref
const fileInput = ref(null);
// 注意:请确认profile变量已在当前作用域正确定义
const form = ref({
  first_name: profile.userProfile.first_name,
  last_name: profile.userProfile.last_name,
  photo: null
});

function handleImageSelect() {
  // 读取选中的文件
  form.value.photo = fileInput.value.files[0];
}

const updateProfile = async () => {
  try {
    // 构造FormData实例
    const formData = new FormData();
    // 追加文本字段
    formData.append('first_name', form.value.first_name);
    formData.append('last_name', form.value.last_name);
    // 有选中图片时追加文件字段
    if (form.value.photo) {
      formData.append('photo', form.value.photo);
    }

    const res = await http.put("user/profile", formData, {
      headers: {
        Accept: "application/json"
        // 不要手动配置Content-Type,axios会自动识别FormData并设置正确的请求头
      }
    });

    if (res.data.success) {
      alert(res.data.message);
      router.push("/profile");
    }
  } catch (error) {
    console.log(error);
  }
};
</script>

2. 修正表单配置

修正enctype错误值,去掉重复的事件绑定,核心表单代码如下:

<form
  class="space-y-8 divide-y divide-hrgray"
  enctype="multipart/form-data"
  @submit.prevent="updateProfile"
>
  <div
      class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-center sm:border-t sm:border-hrgray sm:pt-5"
  >
      <label
      for="photo"
      class="block text-sm font-medium text-gray-700"
      >
      Photo
      </label>
      <div class="mt-1 sm:mt-0 sm:col-span-2">
          <div class="flex items-center">
              <input
              ref="fileInput"
              @change="handleImageSelect"
              type="file"
              />
          </div>
      </div>
  </div>

  <div class="pt-8 space-y-6 sm:pt-10 sm:space-y-5">
      <div
          class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-hrgray sm:pt-5"
      >
          <label
          for="first-name"
          class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2"
          >
          First name
          </label>
          <div class="mt-1 sm:mt-0 sm:col-span-2">
          <input
              type="text"
              v-model="form.first_name"
              name="first-name"
              id="first-name"
              autocomplete="given-name"
              class="max-w-lg block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:max-w-xs sm:text-sm border-gray-300 rounded-md"
          />
          </div>
      </div>

      <div
          class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-hrgray sm:pt-5"
      >
          <label
          for="last-name"
          class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2"
          >
          Last name
          </label>
          <div class="mt-1 sm:mt-0 sm:col-span-2">
          <input
              type="text"
              v-model="form.last_name"
              name="last-name"
              id="last-name"
              autocomplete="family-name"
              class="max-w-lg block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:max-w-xs sm:text-sm border-gray-300 rounded-md"
          />
          </div>
      </div>
  </div>

  <div class="pt-5 pb-10">
      <div class="flex justify-end">
          <button
          type="submit"
          class="ml-3 inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-book hover:bg-blue focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
          >
          Save
          </button>
      </div>
  </div>
</form>
兼容处理

如果部分后端框架无法正确解析PUT方法提交的multipart/form-data请求,可以采用方法伪装的方式:将请求改为POST方法,在FormData中追加formData.append('_method', 'PUT'),大部分后端框架(比如Laravel、Rails)都能识别这个参数并按照PUT路由逻辑处理请求。

另外需要检查你封装的http-commonaxios实例,如果全局配置了固定的Content-Type: application/json默认头,要么移除这个固定配置让axios自动适配请求类型,要么在本次请求的headers配置中显式将Content-Type设为undefined,覆盖默认值。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 03:06:16