Logo
Published on

Koa CORS 时为浏览器 Set Cookie

Authors
  • avatar
    Name
    Monster Cone
    Twitter

后端 Set-Cookie 语句很简单,但遇到跨域时就会遇到各种各样的问题。正常情况下我们如下就可以很简单的给浏览器设置一个 cookie

ctx.cookies.set('accessToken', accessToken, {
  expires: new Date(accessTokenExpired),
  httpOnly: false,
})

httpOnly 默认是 true,如果你的 token 本身就是通过 cookie 传递解析可忽略,否则前端 js 无法获取到该 cookie。

在本地开发时并没有什么问题,但发布上线后,就会发现 cookie 无法写入。

1. 后端配置

后端使用 nginx 反向代理时,需要开启 Koa 框架的信任代理

const app = new Koa()
app.proxy = true

在跨域情况下,Set-Cookie 必须配置 sameSite 和 secure 属性,示例如下

ctx.cookies.set('xxx', xxx, {
  expires: new Date(),
  httpOnly: false,
  secure: true,
  sameSite: 'None',
  domain: '.dongxin.co',
})

如果前端域名和 API 域名不同,我们还需要配置 domain,domain 使用.xxx.xxx 的格式,保证你的前端域名和 API 域名都能匹配。

2. 前端配置

前端在请求时也必须携带 cookie 才行

axios 配置

const apiInstance = axios.create({
  baseURL: process.env.NODE_ENV === 'production' ? 'https://xxx-api.xxx.xxx/v1' : '/v1', // 设置API的基本URL
  timeout: 5000,
  withCredentials: true, // 携带Cookie
})

fetch 配置

fetch('https://xxx.xxx.xxx/v1', {
  credentials: 'include', // 携带Cookie
})

它们默认都是不携带 cookie 的,如果不想在所有请求中都携带 cookie,可以在需要 Set-Cookie 的请求时配置即可。

3. Nginx 配置

server {
    server_name xxx-api.xxx.xxx;
    proxy_pass_header Set-Cookie;

    add_header Access-Control-Allow-Origin https://xxx.xxx.xxx always;
    add_header Access-Control-Allow-Credentials true always;

    ...othen config

    location / {
        ...other config
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
  • proxy_pass_header:将 Set-Cookie 响应头转发到客户端
  • Access-Control-Allow-Origin: 该响应头必须为具体域名,通常为前端的访问域名
  • Access-Control-Allow-Credentials: 允许携带 cookie
  • proxy_set_header: 转发请求的协议,让后端根据协议配置 secure

完成上述配置后,我们就跨域在请求得到响应时,在浏览器看到响应的 cookie。

当前文章并没有 CORS 配置,默认已经能够在 CORS 情况下请求成功。

常见的错误情况

1. 接口响应 200,但却出现 CORS 错误

这种情况下我们能看到接口响应了 200,但没有响应数据,并且 Set-Cookie 没有效果,这是因为我们配置了双重跨域,在 Nginx 和后端都开启了跨域。

这是因为 domain 无法匹配当前域名或者 expires 为当前时间导致被清空

最后,跨域 Set-Cookie 重点就是前端携带 cookie 请求,Nginx 允许携带 Credentials,domain 域名匹配,sameSite 为"None"。