Laravel中AJAX二次POST提交出现CSRF Token不匹配问题排查
First off, let's break down why you're seeing this token mismatch issue. Laravel ties the CSRF token to your user's session, and by default, it only regenerates the token on successful authentication (to prevent session fixation). However, in some edge cases—like if your server-side logic is inadvertently regenerating the session on failed requests, or if the client-side token isn't syncing with the server's session token after a failed submission—you might run into this problem.
You don't necessarily need to refresh the CSRF token on every AJAX request, but updating it after each request (success or failure) can prevent this mismatch from happening. Here are a few actionable fixes:
1. Update the Form's CSRF Token After Each AJAX Request
Laravel automatically sends the latest CSRF token in the X-CSRF-Token response header. You can grab this value after each AJAX call and update the hidden _token input in your form:
Modify your JS code to include this in both success and error callbacks:
$(document).on('submit','.registration-form',function(e){ e.preventDefault(); var form = $(this); var form_url = $(this).attr("action"); var form_values = $(this).serialize(); $.ajax({ url: form_url, type: 'POST', data: form_values, dataType: 'json', async: false, // Note: async:false is deprecated—consider removing this success: function(result, status, xhr){ // Update CSRF token from response header var newToken = xhr.getResponseHeader('X-CSRF-Token'); if(newToken){ form.find('input[name="_token"]').val(newToken); } console.log(result); if(result['status']==true){ location.href = result['redirect']; } else{ form.find(".form-details").show().html(result['message']); } }, error: function(ts) { // Update CSRF token even on error var newToken = ts.getResponseHeader('X-CSRF-Token'); if(newToken){ form.find('input[name="_token"]').val(newToken); } console.log(ts.responseText); } }); });
2. Use the Meta Tag Approach for CSRF Tokens
A more robust way to handle AJAX CSRF tokens is to store the token in a meta tag and include it in your AJAX headers instead of relying on the form's hidden input. This avoids issues with stale form tokens:
First, add this meta tag to your HTML head:
<meta name="csrf-token" content="{{ csrf_token() }}">
Then, modify your AJAX code to send the token in the X-CSRF-TOKEN header:
$(document).on('submit','.registration-form',function(e){ e.preventDefault(); var form = $(this); var form_url = $(this).attr("action"); var form_values = $(this).serialize(); $.ajax({ url: form_url, type: 'POST', data: form_values, dataType: 'json', async: false, headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') }, success: function(result){ console.log(result); if(result['status']==true){ location.href = result['redirect']; } else{ form.find(".form-details").show().html(result['message']); } }, error: function(ts) { // Refresh the meta tag token if needed var newToken = ts.getResponseHeader('X-CSRF-Token'); if(newToken){ $('meta[name="csrf-token"]').attr('content', newToken); } console.log(ts.responseText); } }); });
You can also set this header globally for all AJAX requests to avoid repeating code:
$.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } });
3. Check for Unnecessary Session Regeneration
Double-check your server-side code (like login controller or middleware) to make sure you're not accidentally regenerating the session on failed login attempts. For example, avoid calling session()->regenerate() unless it's necessary (like after a successful login).
By default, Laravel's Auth::attempt() method regenerates the session only on successful authentication, so if you're using that, you should be fine. But if you have custom code that's regenerating the session on failure, that would cause the token mismatch.
内容的提问来源于stack exchange,提问作者itsover9000




