如何用单个方法实现多表关联数据插入及解决Axios 405错误
405错误核心根因
- 405代表“请求方法不被允许”,触发原因主要有三类:
- 后端
/api/commander路径注册的路由不支持POST方法 - 前端请求路径拼写错误,和后端注册的路由路径不匹配
- Laravel CSRF校验拦截返回的异常状态码,被前端Axios误识别为405
- 后端
全链路代码现存问题(不止405)
- 前端提交逻辑完全缺失核心业务数据:当前
store()方法仅附加了made_by一个字段,没有把购物车商品列表、优惠金额等后端必须的入参传给接口 - 控制器逻辑存在多处语法和逻辑错误:
- 集合转换的闭包没有返回值,导致处理后的变量为空
- 对数组格式的请求数据直接调用
->update()方法,数组本身不存在Eloquent模型的update()能力 - 方法接收的
$id参数,前端请求中没有对应传入,会直接导致路由参数绑定失败 - 分别创建了两个独立的
RestauCommande实例,一个做了赋值但从未入库,另一个用create()方法生成的实例和前者没有关联,最后调用关联方法时会因为没有主键ID导致写入失败
- 缺少数据库事务保障:三张表的写入属于强关联操作,任意一步执行失败都会产生脏数据(比如库存扣减成功但订单未生成)
可直接落地的修正方案
路由层修正
在routes/api.php中明确注册POST方法的路由,去掉多余的必选参数:
use App\Http\Controllers\CommandeController; Route::post('/commander', [CommandeController::class, 'store']);
前端逻辑修正
- 在页面头部引入CSRF Token的meta标签,全局配置Axios默认请求头携带该Token,避免被中间件拦截
- 重写提交逻辑,把购物车全量数据拼入请求参数:
store() { const formData = new FormData(); // 携带操作人ID formData.append( "made_by", document.querySelector("meta[name='users_id']").getAttribute("content") ); // 携带优惠金额 formData.append("remise", this.form.remise ?? 0); // 把购物车列表序列化后作为商品入参传递 formData.append( "produits", JSON.stringify(this.cart.map(item => ({ produit_id: item.id, quantite: item.quantity, prix_unitaire: item.prix }))) ); axios.post("/api/commander", formData) .then(res => { // 提交成功后清空购物车、关闭弹窗 this.cart = []; this.$refs.myModalRefProduit.hide(); }) .catch(err => { console.error("订单提交失败:", err); }) }
后端控制器修正
引入数据库事务保障三表写入的原子性,修正所有逻辑错误:
public function store(Request $request) { return \DB::transaction(function () use ($request) { // 入参校验 $validated = $request->validate([ 'produits' => 'required|array', 'produits.*.produit_id' => 'exists:products,id', 'produits.*.quantite' => 'numeric|min:1', 'remise' => 'nullable|numeric|min:0' ]); // 循环扣减商品库存,同时组装关联表数据 $orderItems = collect($validated['produits'])->map(function ($item) { $product = Produits::find($item['produit_id']); // 执行库存扣减 $product->decrement('stock_actuel', $item['quantite']); // 组装商品行数据 return new CommandesProduits([ 'produit_id' => $item['produit_id'], 'prix_unitaire' => $item['prix_unitaire'], 'quantite' => $item['quantite'], 'total_ligne' => $item['prix_unitaire'] * $item['quantite'] ]); }); // 计算订单总金额 $subTotal = $orderItems->sum('total_ligne'); $grandTotal = $subTotal - $request->input('remise', 0); // 创建订单主表记录 $order = RestauCommande::create([ 'numero_commande' => 'CMDE-' . now()->timestamp, 'date_commande' => now(), 'made_by' => $request->input('made_by'), 'sub_total' => $subTotal, 'grand_total' => $grandTotal, 'remise' => $request->input('remise', 0) ]); // 批量写入关联表数据 $order->produits()->saveMany($orderItems); return response()->json([ 'success' => true, 'order_id' => $order->id, 'message' => '订单创建成功' ]); }); }
内容的提问来源于stack exchange,提问作者Derick T.
相关产品推荐
相关产品推荐

