使用嵌套的AJAX调用时得到TokenMismatchException
。第一个AJAX调用工作正常,但第二个调用总是出错而不是成功。
我想要做的是,当用户从导航栏中的按钮注册时,我希望他转到仪表板或/home
- 这样可以正常工作。但是,当用户填写索引页面上的表格(买东西)时,我希望他:
检查他的输入是否有效,然后检查他是否已登录,如果没有,则弹出注册模式。在他注册后我希望他被重定向到结账页面。
然而,当用户填写购买表格并点击提交时,第一个ajax检查购买表格中的输入是否有效,如果是,则检查他是否登录,如果没有返回401错误。
401被第一个ajax拾取并将流程引导到401处理,其中注册模式弹出以进行注册,即第二个ajax弹出时。在他注册后,由于CSRF令牌不匹配,后端保持返回500。
首先,这是嵌套的ajax:
<script type="text/javascript">
$(document).ready(function(){
$('#topup-form').submit(function(e){
e.preventDefault();
var topup_info = $('form').serialize();
//FIRST AJAX
$.ajax({
url: $('form').attr('action'),
method: 'post',
data: topup_info,
type: 'json',
//if success show success message for user
success: function(result){
alert(result.responseJSON.code);
$('.alert.error').slideUp(200);
$('.alert.success').append("<p class='lead'>Thanks! To checkout we go!</p>").slideDown(200);
},
//for error check if it's 400 (validation) or 401(authentication)
error: function(errorData){
// alert(errorData.responseJSON.code);
if(errorData.responseJSON.code === 400){
var error = errorData.responseJSON.message;
$('.alert.error').text('');
$('.alert.success').slideUp(200);
for (var i in error){
for (var j in error[i]) {
var message = error[i][j];
$('.alert.error').append("<p class='lead'>" + message + "<p>");
}
}
$('.alert.error').slideDown(00);
}//end error 400
//for authentication failure, show registeration modal
else if (errorData.responseJSON.code === 401) {
//change somethings in registeration modal
$('#myModalLabel').html('Please Login First');
$('#register').trigger('click');
document.getElementById('formRegister').action = "{{ route('user.regtopup') }}";
//when registeration form is submitted..
$('#formRegister').submit(function(e){
e.preventDefault();
//fire 2nd ajax
$.ajax({
url: $('#formRegister').attr('action'),
method: 'post',
data: $('form').serialize(),
type: 'json',
success: function(result){
alert('success!!!');
},
//it keeps going to error! complaining about csrf token mismatch
error: function(result){
console.log(JSON.stringify(result));
},
})//end of 2nd ajax
});//end of 2nd submit
}//end of 401
}//end of error
});//end of first ajax
});//end of first submit
$.ajaxSetup({
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
}
})
});
</script>
其次,这是检查输入有效性的控制器,并在未注册时返回401:
public function etiPost(Request $request) {
$validator = [
'topupAmount'=> 'required|integer|between:10,500',
'phonenumber'=> 'required|regex:/^05[602][0-9]{7}$/',
];
$inputs = $request->all();
Log::info($inputs);
$validator = Validator::make($inputs, $validator);
if($validator->fails()){
return Response::json([
'error' => true,
'message' => $validator->messages(),
'code' => 400
], 400);
}
elseif (Auth::check()) {
return view('pages.checkout', compact('inputs'));
}
else {
return Response::json([
'error' => true,
'message' => "Please login first",
'code' => 401
], 401);
}
}
这是重载的register
方法,在注册成功时返回JSON。这是500返回的地方!当我记录返回的JSON时,它会以正常的200响应出现,但是它会向第二个ajax发出“Whoops”500错误!用户已在数据库中成功注册,但此方法返回500,该调用由ajax调用的error
部分捕获。
/**
* Handle a registration request for the application (overloaded).
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function register(Request $request)
{
$validator = $this->validator($request->all());
if ($validator->fails()) {
$this->throwValidationException(
$request, $validator
);
}
$this->guard()->login($this->create($request->all()));
// return response()->json();
return response()->json(['msg' => 'Success! You have been registered!'], 200);
}
为简洁起见,我不会包含表单,但请放心,我在HTML的head
中添加了所有CSRF输入标记和元标记。
为避免这种情况,我应该采取哪些不同的做法?第一个ajax工作,但第二个不工作。
答案 0 :(得分:0)
为每个ajax调用设置标头标记
headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') },
另请注意,您必须在模板中添加mete标记
您可以在模板中添加这样的元令牌
<meta name="csrf-token" content="{{ csrf_token() }}">
如果您仍想禁用csrf令牌,那么
从CSRF保护中排除URI
有时您可能希望从CSRF保护中排除一组URI。例如,如果您使用Stripe处理付款并使用其webhook系统,则需要从CSRF保护中排除Stripe webhook处理程序路由,因为Stripe将不知道要向您的路由发送什么CSRF令牌。
通常,您应将这些类型的路由放在RouteServiceProvider应用于routes / web.php文件中所有路由的Web中间件组之外。但是,您也可以通过将其URI添加到VerifyCsrfToken中间件的$ except属性来排除路由:
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
class VerifyCsrfToken extends BaseVerifier
{
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [
'stripe/*',
];
}
如果您提供'stripe/*',
,则代替'/*'
,它将禁用所有的令牌
有关更多详细信息:
答案 1 :(得分:0)
请在ajax调用之前按照jquery中的代码进行操作
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
不建议在meta中添加CSRF令牌,因为所有页面都不包含提交值的表单,因此请使用此解决方案,以便您只能将CSRF用于js透视图。
谢谢