Laravel AJAX请求遇419(unknown status)CSRF令牌不匹配问题求助
Laravel AJAX文件上传出现419 CSRF令牌不匹配问题排查
问题描述
在Laravel项目中使用AJAX上传文件时,向POST http://127.0.0.1:8000/admin/upload/services发起请求,出现419(unknown status)错误,提示CSRF令牌不匹配,但已经配置了CSRF令牌,困扰数小时,求问题根源。
相关代码
AJAX代码
$.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } }); /* Upload file */ $("#upload").change(function(){ const form = new FormData(); console.log($(this)[0].files[0]); form.append('file', $(this)[0].files[0]); $.ajax({ url: '/admin/upload/services', processData: false, contentType: false, type: 'POST', dataType: 'JSON', data: form, success: function(results){ if(results.error == false){ $("#image_show").html( ` <a href="${results.urlFile}" target="_blank"> <img src="${results.urlFile}" width="100px"> </a> `); $("#thumb").val(results.urlFile); } else{ alert(results.messageError); } } }); });
add.blade.php代码
@extends('admin.layout.main') @section('header') <script src="/ckeditor/ckeditor.js"></script> @endsection @section('content') <form action="{{ route('product.store') }}" method="POST"> @csrf <div class="card-body"> <div class="row"> <div class="col-md-6"> <div class="form-group"> <label for="menu">Tên Sản Phẩm</label> <input type="text" name="name" value="{{ old('name') }}" class="form-control" placeholder="Nhập tên sản phẩm"> </div> </div> <div class="col-md-6"> <div class="form-group"> <label>Danh Mục</label> <select class="form-control" name="menu_id"> <option value=""></option> {!! App\Helpers\Helper::recursiveSelectMenu($menus) !!} </select> </div> </div> </div> <div class="row"> <div class="col-md-6"> <div class="form-group"> <label for="menu">Giá Gốc</label> <input type="number" name="price" value="{{ old('price') }}" class="form-control" > </div> </div> <div class="col-md-6"> <div class="form-group"> <label for="menu">Giá Giảm</label> <input type="number" name="price_sale" value="{{ old('price_sale') }}" class="form-control" > </div> </div> </div> <div class="form-group"> <label>Mô Tả </label> <textarea name="description" class="form-control">{{ old('description') }}</textarea> </div> <div class="form-group"> <label>Mô Tả Chi Tiết</label> <textarea name="content" id="content" class="form-control">{{ old('content') }}</textarea> </div> <div class="form-group"> <label for="menu">Ảnh Sản Phẩm</label> <input type="file" class="form-control" name="file" id="upload"> <div id="image_show"></div> <input type="hidden" name="thumb" id="thumb"> </div> <div class="form-group"> <label>Kích Hoạt</label> <div class="custom-control custom-radio"> <input class="custom-control-input" value="1" type="radio" id="active" name="active" checked=""> <label for="active" class="custom-control-label">Có</label> </div> <div class="custom-control custom-radio"> <input class="custom-control-input" value="0" type="radio" id="no_active" name="active" > <label for="no_active" class="custom-control-label">Không</label> </div> </div> </div> <div class="card-footer"> <button type="submit" name="submit" class="btn btn-primary">Thêm Sản Phẩm</button> </div> </form> @endsection @section('footer') <script> CKEDITOR.replace('content'); </script> @endsection
header.blade.php代码
<meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{{ $title }}</title> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700&display=fallback"> <link rel="stylesheet" href="/template/admin_asset/plugins/fontawesome-free/css/all.min.css"> <link rel="stylesheet" href="/template/admin_asset/plugins/icheck-bootstrap/icheck-bootstrap.min.css"> <link rel="stylesheet" href="/template/admin_asset/dist/css/adminlte.min.css?v=3.2.0"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/admin-lte@3.2/dist/css/adminlte.min.css"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v6.5.2/css/all.css"> <meta name="csrf-token" content="{{ csrf_token() }}"> @yield('header')
web.php路由代码
Route::middleware('auth')->group(function () { Route::prefix('admin')->group(function () { Route::post('/upload/services', [UploadController::class, 'store']); }); });
问题排查与解决方案
1. AJAX代码执行时机错误
你的$.ajaxSetup代码如果是在页面DOM未完全加载时执行(比如放在<head>里),此时$('meta[name="csrf-token"]')还未渲染,会获取到undefined,导致请求头里的CSRF令牌为空,触发验证失败。
修复方案:把AJAX代码包裹在$(document).ready()中,确保DOM加载完成后再执行:
$(document).ready(function() { $.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } }); /* Upload file */ $("#upload").change(function(){ const form = new FormData(); console.log($(this)[0].files[0]); form.append('file', $(this)[0].files[0]); $.ajax({ url: '/admin/upload/services', processData: false, contentType: false, type: 'POST', dataType: 'JSON', data: form, success: function(results){ if(results.error == false){ $("#image_show").html( ` <a href="${results.urlFile}" target="_blank"> <img src="${results.urlFile}" width="100px"> </a> `); $("#thumb").val(results.urlFile); } else{ alert(results.messageError); } } }); }); });
2. 验证CSRF令牌是否正确获取
打开浏览器控制台,执行console.log($('meta[name="csrf-token"]').attr('content')),查看输出是否为有效令牌字符串:
- 如果输出
undefined:检查header.blade.php中的<meta name="csrf-token" content="{{ csrf_token() }}">是否正确渲染,确保{{ csrf_token() }}能生成令牌(可以查看页面源码确认)。 - 如果输出令牌但仍报错:尝试在FormData中直接添加令牌,作为备选验证方式:
form.append('_token', $('meta[name="csrf-token"]').attr('content'));
3. 确认用户登录状态
你的路由使用了auth中间件,若当前用户未登录,session中的CSRF令牌会失效,导致验证失败。确保发起AJAX请求时用户处于已登录状态。
4. 清除浏览器缓存与Cookie
有时候浏览器缓存的旧CSRF令牌会导致冲突,清除浏览器缓存和Cookie后重新测试。
内容的提问来源于stack exchange,提问作者nam156
相关产品推荐
相关产品推荐

