You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel中使用Guzzle Client集成reCAPTCHA后重新提交问题咨询

Fixing reCAPTCHA Form Resubmission Issues in Laravel

Got it, let's break down how to fix this reCAPTCHA form resubmission problem you're hitting. The root cause here is straightforward: reCAPTCHA response tokens are single-use only. Once you send a token to Google's verification API and it passes, that token is invalidated forever. So when a user refreshes the page, hits back and resubmits, or accidentally clicks submit twice, the same token gets sent again—and Google will reject it.

Here are three actionable solutions tailored to your Laravel setup, ordered by best practice priority:

1. Implement the Post/Redirect/Get (PRG) Pattern

This is the gold standard for preventing form resubmissions in web apps, and it plays nicely with reCAPTCHA. Instead of returning a view directly after successful form submission, you redirect the user to a new route (usually the same form page or a success page) and flash a success message. This way, refreshing the page only triggers a GET request, not a repeat POST with the old token.

How to set it up:

In your controller's form handling method, replace any direct return view() calls after successful validation with a redirect:

public function submitForm(Request $request)
{
    $request->validate([
        // Your other validation rules
        'g-recaptcha-response' => 'required|recaptcha'
    ]);

    // Process your form data here (save to DB, send emails, etc.)

    // Redirect back to the form page with a success message
    return redirect()->route('form.page')->with('success', 'Your form was submitted successfully!');
}

Then in your form view, display the flashed message and let reCAPTCHA reload naturally:

@if(session('success'))
    <div class="alert alert-success">
        {{ session('success') }}
    </div>
@endif

<!-- Your form here -->
<form method="POST" action="{{ route('form.submit') }}" id="your-form-id">
    @csrf
    <!-- Form fields -->
    <div class="g-recaptcha" data-sitekey="{{ env('RECAPTCHA_SITE_KEY') }}"></div>
    <button type="submit">Submit</button>
</form>

Since the page is reloaded via redirect, reCAPTCHA will generate a brand new token automatically.

2. Track Used Tokens in Session (Backend Safety Net)

Even with PRG, there's an edge case where a user might resubmit a new form with a token that was already used (though unlikely). To add an extra layer of protection, you can track validated tokens in the user's session and reject any repeats before even calling Google's API.

Modify your custom reCAPTCHA validator:

Validator::extend('recaptcha', function ($attribute, $value, $parameters, $validator) {
    // First check if this token was already used in the current session
    if (session()->has('used_recaptcha_tokens.' . $value)) {
        return false;
    }

    $client = new Client();
    try {
        $response = $client->post(env('RECAPTCHA_VERFIY_URL'), [
            'form_params' => [
                'secret' => env('RECAPTCHA_SECRET_KEY'),
                'response' => $value
            ]
        ]);
        $body = json_decode((string)$response->getBody());
        
        if ($body->success) {
            // Store the valid token in session with a 1-hour expiration
            session()->put('used_recaptcha_tokens.' . $value, true, 3600);
            return true;
        }
        
        return false;
    } catch (\Exception $e) {
        // Handle API errors (e.g., network issues) gracefully
        return false;
    }
});

This ensures that even if a duplicate token makes it to your backend, you'll reject it immediately without wasting a call to Google's API.

3. Disable Submit Button on Click (Frontend Guard)

Add a simple JavaScript snippet to prevent users from accidentally clicking submit multiple times. This is a frontend-only fix, so it shouldn't be your only defense, but it's a great user experience improvement.

Example code for your form view:

document.getElementById('your-form-id').addEventListener('submit', function(e) {
    const submitBtn = this.querySelector('button[type="submit"]');
    submitBtn.disabled = true;
    submitBtn.textContent = 'Submitting...';
});

This will grey out the button and change its text once the form is submitted, preventing duplicate clicks.


Combining all three approaches will give you a robust solution: PRG handles the core resubmission issue, session tracking adds backend safety, and frontend button disabling reduces user error.

内容的提问来源于stack exchange,提问作者MAX POWER

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:14:13