支付成功后再插入表单数据的Laravel实现问题咨询
问题概述
用户提交表单后会被重定向到PayTabs支付页面,但目前表单数据(Payment记录)和Transaction记录在支付前就被插入数据库,即使用户放弃支付或支付失败,数据依然存在。需求是仅在支付成功后才保存表单相关数据。
解决方案
核心思路是把表单数据暂存在Session中,等支付成功的回调触发时,再将数据写入数据库,同时调整交易记录的创建逻辑。
1. 修改index方法:暂存数据,延迟写入
把原来直接写入数据库的操作全部移除,只生成支付请求并把表单数据暂存到Session:
public function index(Request $request): RedirectResponse { // 生成PayTabs支付请求 $response = $this->request( url: 'https://secure-global.paytabs.com/payment/request', payload: $this->transactionPayload( amount: 0 // 注意:这里金额为0,需根据实际业务调整 ) ); $tranRef = $response->json()['tran_ref'] ?? null; // 把表单数据和交易参考号暂存到Session session([ 'pending_payment' => [ 'tran_ref' => $tranRef, 'user_id' => Auth::id(), 'country_id' => $request->country_id, 'delivery_id' => $request->delivery_id, 'address' => $request->address, 'street' => $request->street, 'home' => $request->home, 'email' => $request->email ] ]); // 可选:先创建未支付的交易记录,用于追踪未完成订单 Transaction::create([ 'paytabs_transaction_reference' => $tranRef, 'paid' => false ]); // 重定向到PayTabs支付页面 return redirect()->away($response['redirect_url']); }
2. 修改return方法:支付成功后写入数据
在支付成功的分支里,从Session取出暂存数据,完成数据库写入操作:
public function return(Request $request): \Illuminate\Contracts\View\View|string { $category = Category::all(); $products = Product::all(); $validSignature = $this->validateSignature($request->all()); if ($validSignature) { if ($request->respStatus == 'A') { // 取出Session中的暂存数据 $pendingData = session('pending_payment'); if (!$pendingData || $pendingData['tran_ref'] !== $request->tranRef) { return view('index', compact('category', 'products'))->with('error', '无效的支付数据'); } // 更新交易记录为已支付 $transaction = Transaction::where('paytabs_transaction_reference', $request->tranRef)->first(); if ($transaction) { $transaction->paid = true; $transaction->save(); } // 更新购物车状态和交易参考号 $cart = Cart::where('user_id', $pendingData['user_id']) ->where('opened', 0) ->first(); if ($cart) { $cart->update([ 'paytabs_transaction_reference' => $request->tranRef, 'opened' => 1 ]); // 创建Payment记录 Payment::create([ 'cart_id' => $cart->id, 'country_id' => $pendingData['country_id'], 'delivery_id' => $pendingData['delivery_id'], 'address' => $pendingData['address'], 'street' => $pendingData['street'], 'home' => $pendingData['home'], 'email' => $pendingData['email'] ]); } // 清除Session中的暂存数据 session()->forget('pending_payment'); return view('index', compact('category', 'products'))->with('success', '支付成功!感谢您的购买。'); } else { // 支付失败,清理暂存数据 session()->forget('pending_payment'); // 可选:删除未支付的交易记录 Transaction::where('paytabs_transaction_reference', $request->tranRef)->delete(); return view('index', compact('category', 'products'))->with('error', $request->respMessage); } } else { session()->forget('pending_payment'); return '无效的交易签名'; } }
额外优化点
- Session有效期:可以给暂存数据设置有效期,比如
session(['pending_payment' => $data], now()->addMinutes(30)),避免无效数据长期占用Session。 - 异常处理:在数据库操作部分添加try-catch块,防止因数据库错误导致流程中断。
- 重复提交防护:可以给表单添加CSRF之外的防重复提交令牌,避免用户多次提交表单。
内容的提问来源于stack exchange,提问作者Raed
相关产品推荐
相关产品推荐

