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

Laravel与Nuxt配置CORS跨域失败:仍报Access-Control-Allow-Origin缺失错误

跨域问题排查与解决

错误信息

http://localhost:8000/sanctum/csrf-cookie 从源 http://localhost:3000 发起的请求被CORS策略阻止:请求的资源上不存在 Access-Control-Allow-Origin 头。

当前配置

Nuxt Axios 配置

import axios from "axios"

export default defineNuxtPlugin((NuxtApp) => {

    axios.defaults.withCredentials = true;
    axios.defaults.withXSRFToken = true;
    axios.defaults.baseURL = 'http://localhost:8000'

    return {
        provide: {
            axios: axios
        },
    }
})

Laravel CORS 配置

'paths' => [
    'api/*',
    '/login',
    '/register',
    '/logout',
    '/sanctum/csrf-cookie'
],

'allowed_methods' => ['*'],

'allowed_origins' => [env('FRONTEND_URL', 'http://localhost:3000')],

'allowed_origins_patterns' => [],

'allowed_headers' => ['*'],

'exposed_headers' => [],

'max_age' => 0,

'supports_credentials' => true,
];

尝试过的代理配置

代理中间件文件 server-middleware/api-proxy.js

const axios = require('axios');

module.exports = async function (req, res) {
    const { data, headers } = await axios({
        baseURL: 'http://localhost:8000',
        url: req.url,
        method: req.method,
        headers: {
            ...req.headers,
            'Access-Control-Allow-Origin': 'http://localhost:3000',
            'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
            'Access-Control-Allow-Headers': 'Content-Type',
        },
        data: req.body || null,
    });

    Object.keys(headers).forEach((key) => {
        res.setHeader(key, headers[key]);
    });

    res.end(JSON.stringify(data));
};

Nuxt 配置文件 nuxt.config.ts

serverMiddleware: [
    {
      path: '/api',
      handler: '~/server-middleware/api-proxy.js',
    },
],

问题

按上述配置后仍出现相同跨域错误,代理配置也未解决问题。


排查与解决步骤

1. 确保Laravel配置生效

  • 检查.env文件中FRONTEND_URL是否准确设置为http://localhost:3000,无多余斜杠或空格
  • 执行php artisan config:clear清除配置缓存,重启Laravel服务,避免旧配置残留

2. 修正Nuxt Axios配置

避免直接修改全局axios实例,改用独立实例:

import axios from "axios"

export default defineNuxtPlugin(() => {
    const instance = axios.create({
        baseURL: 'http://localhost:8000',
        withCredentials: true,
        withXSRFToken: true
    })
    return {
        provide: {
            axios: instance
        }
    }
})

如果使用Nuxt 3内置的useFetch/useAsyncData,需显式配置凭证:

const { data } = await useFetch('/sanctum/csrf-cookie', {
    baseURL: 'http://localhost:8000',
    credentials: 'include'
})

3. 修复代理逻辑错误

当前代理的CORS头配置逻辑颠倒,正确写法如下(处理OPTIONS预检请求+转发响应):

const axios = require('axios');

module.exports = async function (req, res) {
    // 处理OPTIONS预检请求
    if (req.method === 'OPTIONS') {
        res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
        res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
        res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-XSRF-TOKEN');
        res.setHeader('Access-Control-Allow-Credentials', 'true');
        return res.end();
    }

    try {
        const { data, headers } = await axios({
            baseURL: 'http://localhost:8000',
            url: req.url,
            method: req.method,
            headers: {
                ...req.headers,
                Origin: 'http://localhost:8000' // 伪装源避免Laravel CORS校验问题
            },
            data: req.body || null,
            withCredentials: true
        });

        // 添加CORS响应头
        res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
        res.setHeader('Access-Control-Allow-Credentials', 'true');
        // 转发Laravel其他响应头
        Object.keys(headers).forEach(key => {
            if (!['Access-Control-Allow-Origin', 'Access-Control-Allow-Credentials'].includes(key)) {
                res.setHeader(key, headers[key]);
            }
        });

        res.end(JSON.stringify(data));
    } catch (err) {
        res.status(err.response?.status || 500).end(JSON.stringify(err.response?.data || { message: 'Proxy error' }));
    }
};

同时修改前端请求路径为代理路径,比如将/sanctum/csrf-cookie改为/api/sanctum/csrf-cookie

4. 检查Sanctum状态域配置

打开config/sanctum.php,确保stateful包含前端域名:

'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
    '%s%s',
    'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
    env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
))),

执行php artisan config:clear使配置生效

5. 浏览器端验证

  • 打开开发者工具Network标签,查看csrf-cookie请求的Request Headers中Origin是否为http://localhost:3000
  • 检查Response Headers是否存在Access-Control-Allow-Origin和Access-Control-Allow-Credentials
  • 使用隐身模式测试,避免缓存影响

内容的提问来源于stack exchange,提问作者Adrian Cerush

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 13:32:03