迁移到新服务器后,我的灯丝应用程序遇到了一个持续存在的问题。使用结帐会话处理 Stripe Webhook 时,尤其会出现此问题。尽管进行了多次配置并尝试解决它,但问题仍然没有解决。我的应用程序使用 StripeController.php 和自定义路由进行结账会话。用户可以购买商品,直接结帐,如果结帐成功,则 webhook 会返回。但每次将 Webhook (checkout.session.completed) 发送到我的应用程序时,都会导致 HTTP 419 错误,并显示消息“页面已过期”。我检查了服务器日志(访问和错误日志),并可以确认 Webhook 请求上的 419 错误。灯丝日志文件没有显示错误。
设置:
我感谢社区的任何建议。我的想法已经用完了,我希望有人能够提供一些见解或提出不同的方法来解决这个问题。
应用程序/Http/Controllers/StripeController.php:
<?php
namespace App\Http\Controllers;
use App\Models\Ecg;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Stripe\Checkout\Session;
use Stripe\Stripe;
use Stripe\Webhook;
class StripeController extends Controller
{
public function createCheckoutSession(Request $request)
{
// Setze den API-Schlüssel über die Config
Stripe::setApiKey(config('services.stripe.secret'));
$amount = $request->query('amount');
$ecgId = $request->query('ecg_id'); // Get the ECG ID from the query parameters
$session = Session::create([
'payment_method_types' => ['card'],
'line_items' => [[
'price_data' => [
'currency' => 'eur',
'product_data' => [
'name' => 'EKG-Befundung',
],
'unit_amount' => $amount * 100, // amount in cents
],
'quantity' => 1,
]],
'mode' => 'payment',
'success_url' => route('payment.success', ['ecg_id' => $ecgId]),
'cancel_url' => route('payment.cancel'),
'metadata' => [
'ecg_id' => $ecgId, // Store the ECG ID in metadata
],
]);
return redirect()->away($session->url);
}
public function success(Request $request)
{
$ecgId = $request->query('ecg_id');
return view('payment.success', ['ecg_id' => $ecgId]);
}
public function cancel()
{
return view('payment.cancel');
}
public function handleWebhook(Request $request)
{
Stripe::setApiKey(config('services.stripe.secret'));
$endpointSecret = config('services.stripe.webhook_secret');
$payload = $request->getContent();
$sigHeader = $request->header('Stripe-Signature');
try {
$event = Webhook::constructEvent($payload, $sigHeader, $endpointSecret);
} catch (\UnexpectedValueException $e) {
return response()->json(['error' => 'Invalid payload'], 400);
} catch (\Stripe\Exception\SignatureVerificationException $e) {
return response()->json(['error' => 'Invalid signature'], 400);
}
switch ($event->type) {
case 'checkout.session.completed':
$session = $event->data->object;
$ecgId = $session->metadata->ecg_id;
$ecg = Ecg::find($ecgId);
if ($ecg) {
$ecg->isPaid = true; // Update the isPaid property
$ecg->save();
}
break;
default:
Log::warning('Unhandled event type: ' . $event->type);
}
return response()->json(['status' => 'success']);
}
}
应用程序/Http/中间件:
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [
'/webhook',
'webhook',
'webhook/*',
];
}
路线/web.php:
<?php
use App\Http\Controllers\InvoiceController;
use App\Http\Controllers\ReportController;
use App\Http\Controllers\StripeController;
use Illuminate\Support\Facades\Route;
Route::get('/invoices/{id}/download', [InvoiceController::class, 'downloadPdf'])->name('invoices.download');
Route::get('/reports/{id}/download', [ReportController::class, 'downloadReportPdf'])->name('reports.download');
Route::get('/create-checkout-session', [StripeController::class, 'createCheckoutSession'])->name('create.checkout.session');
Route::get('/payment-success', [StripeController::class, 'success'])->name('payment.success');
Route::get('/payment-cancel', [StripeController::class, 'cancel'])->name('payment.cancel');
// Define the POST route for the webhook
Route::post('/webhook', [StripeController::class, 'handleWebhook'])->name('webhook.handle');
.env:
APP_ENV=production
APP_KEY=xxx
APP_DEBUG=true
APP_TIMEZONE=Europe/Berlin
APP_URL=https://app.domain.de
APP_LOCALE=de
APP_FALLBACK_LOCALE=de
APP_FAKER_LOCALE=de_DE
APP_MAINTENANCE_DRIVER=file
# APP_MAINTENANCE_STORE=database
STRIPE_SECRET=xxx
STRIPE_WEBHOOK_SECRET=xxx
BCRYPT_ROUNDS=12
LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=sqlite
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_DATABASE=laravel
# DB_USERNAME=root
# DB_PASSWORD=
SESSION_DRIVER=cookie
SESSION_LIFETIME=120
SESSION_DOMAIN=.domain.de
SESSION_SAME_SITE=None
SESSION_SECURE_COOKIE=true
# SESSION_PATH=/
BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
QUEUE_CONNECTION=sync
CACHE_STORE=database
CACHE_PREFIX=
到目前为止我尝试过的:
我自己找到并修复了错误。在最新的 Laravel 中,现在必须将其插入“bootstrap/app.php”文件中,而不是在VerifyCsrfToken.php 文件中设置 Csrf 异常。