Laravel中使用Fetch API提交表单遇POST路由方法支持错误求助
我在Laravel中尝试通过Fetch API提交表单,但始终无法成功。原本不使用Fetch时表单能正常提交,但本次需求必须用Fetch实现。移除表单的action="{{ URL('/process') }}"属性仅依赖Fetch提交时,出现错误提示:The POST method is not supported for this route. Supported methods: GET, HEAD.
以下是我的相关代码:
表单代码
<form action="{{ url('/process')}}" method="POST"> @csrf <div class="form-container"> <div class="form-item"> <label for="name">Full Name<span class="required">*</span></label> <input type="text" name="name" id="name" placeholder="Enter your name" /> </div> <div class="form-item"> <label for="email">Email<span class="required">*</span></label> <input type="email" name="email" id="email" placeholder="Enter your email address" required /> </div> </div> <div class="form-container"> <button type="submit">Submit</button> </div> </form>
Fetch API代码
form.addEventListener("submit", (e) => { e.preventDefault(); const csrfToken = document.querySelector("input[name='_token']").value; fetch("success.blade.php", { method: "post", body: JSON.stringify(process), headers: { "Content-Type": "application/json", "X-CSRF-Token": csrfToken, }, }) .then((response) => { console.log(response); return response.text(); }) .then((text) => { return console.log(text); }) .catch((error) => console.error(error)); }
路由配置
Route::get('/', [ContactController::class, 'create']); Route::get('/all', [ContactController::class, 'getAll']); Route::post('/process', [ContactController::class, 'store']);
ContactController.php代码
public function store(Request $request) { $contact = Contact::create($request->input()); $message = 'Thank you for your message! We will review your submission and respond to you in 24-48 hours.'; if ($request->ajax()) { return response()->json(compact('message')); } return view('success'); }
另外,我创建了success.blade.php用于显示提示信息,但不确定使用Fetch时是否还需要该文件。
问题分析与修复方案
1. Fetch请求地址错误
你当前Fetch请求的是success.blade.php,但Laravel的视图文件不能直接通过POST请求访问,必须通过路由定义的/process接口处理请求。把请求地址改为/process即可。
2. 请求体数据未正确收集
代码中的JSON.stringify(process)里的process是未定义变量,导致提交的数据为空。可以通过FormData快速收集表单数据,或者手动构建数据对象。
3. 请求头与后端接收方式不匹配
如果设置Content-Type: application/json,后端需要用$request->json()获取数据;如果用FormData,浏览器会自动设置正确的请求头,后端可以用$request->input()正常接收数据,更符合Laravel表单处理的习惯。
4. 可选:移除表单的action属性
虽然已经用e.preventDefault()阻止了默认提交行为,但移除action属性可以避免混淆,让代码更清晰。
关于success.blade.php
使用Fetch时,后端可以直接返回JSON格式的提示信息,前端通过JS在当前页面展示提示(比如弹窗、页面内提示框),无需跳转页面。如果需要跳转至成功页面,可以在Fetch请求成功后用window.location.href = '/success'实现,此时success.blade.php仍需保留,同时需要在路由中添加对应的GET路由:
Route::get('/success', function () { return view('success'); });
修复后的代码示例
修复后的Fetch代码
const form = document.querySelector('form'); form.addEventListener("submit", (e) => { e.preventDefault(); const csrfToken = document.querySelector("input[name='_token']").value; // 用FormData收集表单数据 const formData = new FormData(form); fetch("/process", { method: "POST", body: formData, headers: { "X-CSRF-Token": csrfToken, // 无需手动设置Content-Type,FormData会自动处理 }, }) .then((response) => { if (!response.ok) { throw new Error('请求失败'); } return response.json(); }) .then((data) => { console.log(data.message); // 页面内展示提示,比如创建一个提示元素 const alertDiv = document.createElement('div'); alertDiv.textContent = data.message; alertDiv.style.color = 'green'; form.appendChild(alertDiv); // 如需跳转成功页面: // window.location.href = '/success'; }) .catch((error) => console.error(error)); });
调整后的控制器代码
public function store(Request $request) { // 先验证表单数据,避免无效数据存入数据库 $validated = $request->validate([ 'name' => 'required|string', 'email' => 'required|email', ]); $contact = Contact::create($validated); $message = 'Thank you for your message! We will review your submission and respond to you in 24-48 hours.'; // 针对Fetch请求直接返回JSON return response()->json(compact('message')); // 如果需要同时支持普通表单提交和Fetch请求,保留以下判断: // if ($request->wantsJson()) { // return response()->json(compact('message')); // } // return view('success'); }
内容的提问来源于stack exchange,提问作者John White

