Vue + Egg.js 跨域登录踩坑实录 – Cookie

本地开发时,前端跑在 127.0.0.1:8080,后端在 7001 端口——看似简单,但一涉及登录态(Cookie),跨域就成了“拦路虎”。

很多同学在搭建前后端分离项目时,会遇到这样一个典型场景:

  • 前端 Vue 应用运行在 http://127.0.0.1:8080
  • 后端 Egg.js 服务运行在 http://127.0.0.1:7001
  • 首次访问主页 → 提示登录 → 提交账号密码 → 后端设置 Cookie → 下次自动携带 Cookie 实现“已登录”状态

听起来很合理,但实际开发中却频频报错:Cookie 没带上、后端读不到、浏览器显示 “Provisional headers are shown”……

今天,我们就来彻底梳理这个流程,并解决三大核心问题!


🧭 一、正确设计:登录态如何流转?

正常流程应为:

  1. 首次 GET 请求/
    → 后端检查无 Cookie → 返回 { code: 401, msg: '请登录' }
    → 前端弹出登录框
  2. 用户 POST 登录/login
    → 前端发送用户名/密码
    → 后端验证成功 → 设置 Cookie(含用户 ID) → 返回 { code: 200 }
  3. 后续请求自动携带 Cookie
    → 浏览器自动在请求头中带上 Cookie: userId=xxx
    → 后端读取 Cookie → 识别用户 → 返回个性化内容

✅ 关键点:Cookie 必须在跨域场景下正确设置 + 正确携带 + 正确读取


⚠️ 二、三大高频问题 & 解决方案

现象:后端明明设置了 Set-Cookie,但浏览器 DevTools 的 Application → Cookies 里看不到。

原因
默认情况下,跨域请求不会携带 Cookie,即使服务器返回了 Set-Cookie,浏览器也会忽略。

解决方案

✅ 后端(Egg.js)配置 CORS 支持凭证

安装 egg-cors 插件:

npm i egg-cors

config/plugin.js 中启用:

exports.cors = {
  enable: true,
  package: 'egg-cors',
};

config/config.default.js 中配置:

config.security = {
  csrf: { enable: false }, // 开发阶段可关闭,生产务必开启
};

config.cors = {
  origin: 'http://127.0.0.1:8080', // ⚠️ 必须是具体地址,不能为 '*'
  credentials: true,               // 允许携带 Cookie
  allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH',
};

🔥 重点:

  • origin 不能写 *!当 credentials: true 时,浏览器要求 Access-Control-Allow-Origin 必须是精确匹配的源(如 http://127.0.0.1:8080
  • 不要混用 localhost127.0.0.1!它们在浏览器中被视为不同源。建议统一使用 127.0.0.1

✅ 前端(Vue/Axios)开启凭证

// axios 全局配置
axios.defaults.withCredentials = true;

// 或单次请求
axios.post('http://127.0.0.1:7001/login', data, {
  withCredentials: true
});

❌ 问题 2:后端 setCookie 了,但 ctx.cookies.get() 返回 undefined

现象:抓包看到请求头有 Cookie: userId=abc,但 Egg.js 里 ctx.cookies.get('userId') 却是 undefined

原因
你在 set 时加了选项(如 httpOnly: true),但 get 时没传相同参数!

正确做法

// 设置 Cookie(带选项)
ctx.cookies.set('userId', '123', {
  httpOnly: true,
  signed: false,
  maxAge: 24 * 60 * 60 * 1000, // 1天
});

// 读取时必须传入相同选项!
const userId = ctx.cookies.get('userId', {
  signed: false, // ⚠️ 必须一致
});

💡 默认 signed: true,如果你没用 Egg 的 cookie 签名机制,记得显式设为 false


❌ 问题 3:DevTools 显示 “Provisional headers are shown”

现象:Network 面板中请求头显示灰色,并提示 “Provisional headers are shown”。

真相
这不是错误!这是 Chrome 的一种安全提示,表示“这些 headers 是浏览器预估的,可能与实际发送的不同”。

常见触发场景

  • 页面刚加载,尚未发出真实请求(如 prefetch)
  • 请求被重定向或取消
  • 首次启动服务 + 首次访问(缓存未建立)

是否影响功能?
→ 如果你能收到正确响应(如 200、Cookie 设置成功),那就完全不用管它
→ 它只是 DevTools 的 UI 提示,不代表请求失败

✅ 验证方法:看 Response Headers 是否有 Set-Cookie,Application → Cookies 是否有值。


🛠️ 三、完整代码参考(Egg.js + Vue)

后端:登录接口示例

// app/controller/user.js
async login() {
  const { ctx } = this;
  const { username, password } = ctx.request.body;

  // 简单验证(实际应查数据库)
  if (username === 'admin' && password === '123456') {
    ctx.cookies.set('userId', 'U1001', {
      httpOnly: true,
      signed: false,
      maxAge: 24 * 60 * 60 * 1000,
    });
    ctx.body = { code: 200, msg: '登录成功' };
  } else {
    ctx.status = 401;
    ctx.body = { code: 401, msg: '账号或密码错误' };
  }
}

前端:Axios 配置

// main.js 或 api.js
import axios from 'axios';

axios.defaults.baseURL = 'http://127.0.0.1:7001';
axios.defaults.withCredentials = true; // 关键!

🌟 结语

跨域 + Cookie 是前后端分离开发中的经典难题,但只要记住三点:

  1. CORS 配置必须精确指定 origin,不能用 *
  2. 前端请求必须带 withCredentials: true
  3. Egg.js 读写 Cookie 参数要一致

搞定这些,登录态就能稳稳传递!

细节决定成败,调试就是修“边界条件”的过程。

© 版权声明
THE END
喜欢就支持一下吧
点赞11 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容