基于Laravel实现SQL转JSON并Base64编码调用支付API方案咨询
Laravel+Flutter对接支付API实现电子发票支付流程实操建议
一、Laravel后端核心实现(针对你Laravel不熟的情况,给出最简可运行的代码示例)
1. 搭建订单模型与数据库表
先生成订单模型和迁移文件,包含支付流程必需的核心字段:
php artisan make:model Order -m
打开生成的迁移文件(路径:database/migrations/xxxx_xx_xx_create_orders_table.php),补充字段定义:
public function up() { Schema::create('orders', function (Blueprint $table) { $table->id(); $table->foreignId('user_id')->constrained(); // 关联用户表,可根据实际业务调整 $table->decimal('amount', 10, 2); // 订单金额 $table->string('status')->default('draft'); // 订单状态:draft/processing/paid/failed $table->text('rtp_request')->nullable(); // 暂存Base64编码的支付请求内容 $table->string('payment_token')->nullable(); // 存储支付API返回的令牌 $table->timestamps(); }); }
执行迁移生成数据库表:
php artisan migrate
2. 创建待支付草稿订单
在OrderController中实现创建订单的接口,接收Flutter前端传来的订单数据:
use App\Models\Order; use Illuminate\Http\Request; public function store(Request $request) { // 验证前端参数合法性 $validated = $request->validate([ 'user_id' => 'required|exists:users,id', 'amount' => 'required|decimal:0,2|min:0.01', // 按需添加其他订单字段,如商品ID、发票抬头等 ]); // 创建草稿状态的订单 $order = Order::create(array_merge($validated, ['status' => 'draft'])); return response()->json(['order_id' => $order->id], 201); }
3. 生成指定结构JSON并Base64编码
新建支付服务类解耦业务逻辑,方便后续维护:
php artisan make:service PaymentService
在app/Services/PaymentService.php中实现数据组装与编码逻辑:
namespace App\Services; use App\Models\Order; class PaymentService { public function generateEncodedRequest(Order $order) { // 严格按照支付API要求的结构组装数据 $paymentData = [ 'order_id' => $order->id, 'amount' => $order->amount, 'currency' => 'CNY', // 根据实际币种调整 'invoice_info' => [ 'title' => 'xxx公司', // 从订单或用户数据中提取 'tax_number' => 'xxx' ], 'return_url' => env('APP_URL') . '/api/payment/callback' // 回调地址 ]; // 转JSON并执行Base64编码 $jsonData = json_encode($paymentData); return base64_encode($jsonData); } }
4. 调用支付API获取并存储支付Token
在OrderController中添加发起支付的接口,调用服务类并发送POST请求:
use App\Services\PaymentService; use Illuminate\Support\Facades\Http; public function initiatePayment(Request $request) { $order = Order::findOrFail($request->order_id); if ($order->status !== 'draft') { return response()->json(['error' => '订单状态异常'], 400); } $paymentService = new PaymentService(); $encodedRequest = $paymentService->generateEncodedRequest($order); // 暂存编码后的请求内容 $order->update(['rtp_request' => $encodedRequest]); try { // 调用支付API $response = Http::withHeaders([ 'Authorization' => 'Bearer ' . env('PAYMENT_API_KEY'), 'Content-Type' => 'application/json', ])->post(env('PAYMENT_API_ENDPOINT'), [ 'rtp_request' => $encodedRequest ]); $responseData = $response->json(); if ($response->successful() && isset($responseData['payment_token'])) { // 存储Token并更新订单为处理中状态 $order->update([ 'payment_token' => $responseData['payment_token'], 'status' => 'processing' ]); return response()->json(['payment_token' => $responseData['payment_token']]); } // API返回错误,标记订单为失败 $order->update(['status' => 'failed']); return response()->json(['error' => $responseData['message'] ?? '支付请求失败'], 400); } catch (\Exception $e) { // 捕获网络或未知异常 $order->update(['status' => 'failed']); return response()->json(['error' => '支付请求异常:' . $e->getMessage()], 500); } }
在.env文件中配置支付API的密钥和地址:
PAYMENT_API_KEY=your_payment_api_secret_key PAYMENT_API_ENDPOINT=https://your-payment-processor.com/api/initiate-payment
5. 处理支付回调更新订单状态
新建Webhook控制器处理支付API的回调请求:
php artisan make:controller PaymentWebhookController
在app/Http/Controllers/PaymentWebhookController.php中实现回调逻辑(重点做签名验证,防止伪造请求):
use App\Models\Order; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; public function handle(Request $request) { // 1. 验证支付API的签名(按服务商文档实现,示例用HMAC-SHA256) $signature = $request->header('X-Payment-Signature'); $expectedSignature = hash_hmac('sha256', $request->getContent(), env('PAYMENT_API_KEY')); if (!hash_equals($signature, $expectedSignature)) { Log::warning('支付回调签名验证失败', ['request' => $request->all()]); return response()->json(['status' => 'invalid'], 403); } // 2. 解析回调数据并找到对应订单 $callbackData = $request->json(); $order = Order::where('payment_token', $callbackData['payment_token'])->firstOrFail(); // 3. 根据支付状态更新订单 switch ($callbackData['status']) { case 'success': $order->update(['status' => 'paid']); // 可在此触发电子发票生成、Firebase推送通知等逻辑 break; case 'processing': $order->update(['status' => 'processing']); break; case 'failed': $order->update(['status' => 'failed']); break; } return response()->json(['status' => 'ok']); }
在routes/api.php中注册回调路由,并关闭CSRF验证(第三方API无需CSRF):
use App\Http\Controllers\PaymentWebhookController; Route::post('/payment/callback', [PaymentWebhookController::class, 'handle'])->withoutMiddleware(['csrf']);
二、Flutter前端配合逻辑(你熟悉的部分,给出关键流程)
- 用户下单:调用Laravel的
POST /api/orders接口,传入订单数据,获取order_id - 发起支付:调用Laravel的
POST /api/orders/initiate-payment接口,传入order_id,获取payment_token - 结果同步:
- 若支付API需前端调起支付组件,用
payment_token调用对应SDK完成支付 - 后端回调完成后,通过Firebase Cloud Messaging推送支付状态通知;或前端定时轮询
GET /api/orders/{order_id}接口获取最新状态
- 若支付API需前端调起支付组件,用
三、关键注意事项
- 日志记录:在创建订单、发起支付、回调处理等关键节点添加日志,方便排查问题:
use Illuminate\Support\Facades\Log; Log::info('发起支付请求', ['order_id' => $order->id]); - 数据库事务:创建订单与生成支付请求的步骤可包裹在事务中,保证数据一致性:
DB::transaction(function () use ($validated, $paymentService) { $order = Order::create(array_merge($validated, ['status' => 'draft'])); $encodedRequest = $paymentService->generateEncodedRequest($order); $order->update(['rtp_request' => $encodedRequest]); }); - 异常兜底:所有外部API调用必须添加try-catch,避免流程崩溃
- 环境隔离:开发、测试、生产环境使用不同的支付API密钥,避免误操作
内容的提问来源于stack exchange,提问作者David Desilets
相关产品推荐
相关产品推荐

