Laravel10+Inertia.js+Vue3用户头像上传更新失败求助
Laravel 10 + Inertia.js + Vue 3 头像上传后端收不到文件问题
使用Laravel10、Inertia.js和Vue.js3开发用户头像上传功能时,提交Edit.vue/EditAvatar.vue中的表单后,Laravel的UserController的update方法无法获取到头像文件(通过dd(request())查看发现请求属性为空),导致无法验证和更新新头像。前端通过console.log可以正常查看选中的头像数据,但后端接收不到,问题出在EditAvatar.vue组件的提交逻辑上。
相关代码
Edit.vue
<Layout> <div id="main-div"> <h1 class="text-center">Change Your Data</h1> <EditName :user="user"/> <EditPhoneNumber :user="user"/> <EditEmail :user="user"/> <EditAvatar :user="user"/> </div> </Layout> </template> <script> import Layout from "../../Layout/App.vue"; import { Link } from "@inertiajs/vue3"; import EditName from "./Edit/EditName.vue"; import EditEmail from "./Edit/EditEmail.vue"; import EditPhoneNumber from "./Edit/EditPhoneNumber.vue"; import EditAvatar from "./Edit/EditAvatar.vue"; export default { components: { Layout, EditName, EditEmail, EditPhoneNumber, EditAvatar, Link, }, props: { errors: Object, user: { type: Object, required: true, }, }, }; </script> <style scoped> #main-div { margin-top: 140px; margin-bottom: 140px; } </style>
EditAvatar.vue
<div class="row justify-content-center text-center mx-auto"> <div class="col-12 col-sm-8 col-md-6"> <form enctype="multipart/form-data" class="form mt-5" @submit.prevent="submitAvatar" > <div class="form-group mt-3"> <label for="avatar" class="text-dark">Profile Image:</label ><br /> <input type="file" name="avatar" id="avatar" class="form-control border-primary" @input="form.avatar = $event.target.files[0]" /> </div> <div class="d-flex justify-content-end align-items-center my-3"> <div class="form-group ms-3"> <button type="submit" class="btn btn-warning text-primary py-2 px-3" > Save Profile Image </button> </div> </div> </form> </div> </div> </template> <script setup> import { defineProps } from 'vue'; import { useForm } from "@inertiajs/vue3"; import { router } from '@inertiajs/vue3' const props = defineProps({ user: Object, }); const form = useForm({ avatar: null, }); function submitAvatar() { // console.log("Avatar data:", form.avatar); router.put(`/profile/${props.user.id}/edit`, { _method: 'put', avatar: form.avatar, }); } </script> <style></style>
UserController edit方法
public function edit($id) { $user = User::find($id); $user['avatar'] = asset('storage/' . $user->avatar); return Inertia::render("User/Edit")->with('user', $user); }
UserController update方法
public function update(){ $id = auth()->user()->id; dd(request()); $user = User::find($id); $validated = []; if (request()->has('name')) { $validated = request()->validate([ 'name' => 'required|min:3|max:40', ]); } if (request()->has('phone_number')) { $validated = request()->validate([ 'phone_number' => 'required|min:8|max:20', ]); } if (request()->has('email')) { $validated = request()->validate([ 'email' => 'required|email|unique:users,email', ]); } if (request()->has('avatar')) { $validated = request()->validate([ 'avatar' => 'required|image', ]); $avatarPath = request()->file('avatar')->store('profile', 'public'); $validated['avatar'] = $avatarPath; if($user->avatar) { Storage::disk('public')->delete($user->avatar); } }; if (request()->has('password') && Hash::check(request()->old_password, $user->password)) { request()->validate([ 'old_password' => 'required', 'password' => 'required|min:3|confirmed', ]); $user->update([ 'password' => Hash::make(request()->password), ]); return redirect()->route('home')->with('success', 'Password updated successfully'); } $user->update($validated); return redirect()->route('home')->with('message', 'Profile updated successfully!'); }
问题原因
直接使用router.put传递File对象时,Inertia默认会将请求数据序列化为JSON格式,但JSON无法传输File对象,导致后端接收不到文件数据。
解决方案
修改EditAvatar.vue的提交逻辑,利用Inertia的useForm提供的submit方法来处理文件上传,该方法会自动创建FormData并设置正确的请求头(multipart/form-data):
<script setup> import { defineProps } from 'vue'; import { useForm } from "@inertiajs/vue3"; const props = defineProps({ user: Object, }); const form = useForm({ avatar: null, }); function submitAvatar() { form.put(`/profile/${props.user.id}/edit`, { preserveScroll: true, onSuccess: () => { form.reset('avatar'); // 上传成功后重置文件输入框 }, }); } </script>
额外优化建议
- 后端update方法可以注入
Request实例,代码更规范:
use Illuminate\Http\Request; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Storage; public function update(Request $request){ $user = auth()->user(); $validated = []; if ($request->hasFile('avatar')) { $validated = $request->validate([ 'avatar' => 'required|image|max:2048', // 限制文件大小为2MB ]); if($user->avatar) { Storage::disk('public')->delete($user->avatar); } $validated['avatar'] = $request->file('avatar')->store('profile', 'public'); } // 其他字段的验证逻辑... $user->update($validated); return redirect()->route('home')->with('message', 'Profile updated successfully!'); }
- 前端可以添加文件类型验证,只允许图片文件:
<input type="file" name="avatar" id="avatar" class="form-control border-primary" accept="image/*" <!-- 只允许选择图片文件 --> @input="form.avatar = $event.target.files[0]" />
内容的提问来源于stack exchange,提问作者4leb
相关产品推荐
相关产品推荐

