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

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&amp;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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 17:15:55