React调用Laravel Sanctum登录接口出现419状态码问题求助
问题描述
使用Laravel API + Sanctum开发时,本地通过Postman及curl调用http://127.0.0.1:8000/api/login接口一切正常,但React前端的Login组件用fetch发起POST请求时返回419(unknown status)错误。
curl请求示例:
curl --location --request POST 'http://127.0.0.1:8000/api/login' \ --header 'Accept: application/vnd.api+json' \ --header 'Content: application/vnd.api+json' \ --form 'email="admin@admin.com"' \ --form 'password="passworD34$"'
Login.js代码:
import { Fragment, useState, useRef } from "react"; import classes from './Login.module.css'; const Login = () => { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [message, setMessage] = useState(""); let handleSubmit = async (e) => { e.preventDefault(); const { email, password } = e.target.elements try { const res = await fetch("http://127.0.0.1:8000/api/login", { method: "POST", body: JSON.stringify({ email: email.value, password: password.value }), headers: { "Accept" : "application/vnd.api+json", "Content" : "application/vnd.api+json" }, }); let resJson = await res.json(); // console.log(resJson); return; if (res.status === 200) { setEmail(""); setPassword(""); setMessage("User logged in successfully"); } else { setMessage("Some error occured"); } } catch (err) { console.log(err); } }; return ( <Fragment> <div className={classes['form-holder']}> <div className={classes['form-content']}> <form onSubmit={handleSubmit}> <label>Email</label> <input type="text" id="email" /> <label>Password</label> <input type="text" id="password" /> <button className={classes['btn-primary']} type="submit" value="Login">Login</button> </form> </div> {message} </div> </Fragment> ); } export default Login;
错误提示:
Login.js:16, POST http://127.0.0.1:8000/api/login 419 (unknown status)
问题排查与解决
核心原因
Laravel返回419错误的核心原因是CSRF令牌验证失败,同时你的请求头存在格式错误,双重问题导致报错。
具体修复步骤
1. 处理Sanctum跨域CSRF令牌验证
跨域场景下,React请求必须先获取Laravel的CSRF令牌,再携带令牌发起登录请求:
let handleSubmit = async (e) => { e.preventDefault(); const { email, password } = e.target.elements try { // 先请求获取CSRF令牌 await fetch("http://127.0.0.1:8000/api/csrf-cookie", { credentials: 'include' // 必须携带Cookie,才能保存CSRF令牌 }); const res = await fetch("http://127.0.0.1:8000/api/login", { method: "POST", credentials: 'include', // 携带包含CSRF令牌的Cookie body: JSON.stringify({ email: email.value, password: password.value }), headers: { "Accept" : "application/vnd.api+json", "Content-Type" : "application/json" // 修正请求头键名 }, }); let resJson = await res.json(); if (res.status === 200) { setEmail(""); setPassword(""); setMessage("用户登录成功"); } else { setMessage("登录失败,请检查账号密码"); } } catch (err) { console.log(err); } };
2. 修正请求头错误
原代码中请求头写的"Content" : "application/vnd.api+json"是错误的,正确的键名是Content-Type;如果用JSON.stringify发送JSON数据,对应值应为application/json(若后端要求application/vnd.api+json可替换,但键名必须是Content-Type)。
3. 确认Laravel Sanctum配置
- 修改
config/cors.php,确保允许前端域名并开启凭证支持:'paths' => ['api/*', 'sanctum/csrf-cookie'], 'allowed_methods' => ['*'], 'allowed_origins' => ['http://localhost:3000'], // React项目的本地地址 'allowed_headers' => ['*'], 'supports_credentials' => true, - 修改
.env文件,设置正确的会话和Sanctum域名:SESSION_DOMAIN=127.0.0.1 SANCTUM_STATEFUL_DOMAINS=127.0.0.1:3000
4. 可选:对齐curl的表单提交格式
如果想和curl一样发送表单数据而非JSON,可修改fetch的body部分:
body: new FormData(e.target), // 直接使用表单数据,无需JSON序列化 headers: { "Accept" : "application/vnd.api+json" // 无需手动设置Content-Type,浏览器会自动添加multipart/form-data },
内容的提问来源于stack exchange,提问作者cookie
相关产品推荐
相关产品推荐

