cors

2020 M12 20

简单请求和复杂请求

cors分为简单请求和复杂请求,对于简单请求的限制较少,对于复杂请求的限制较多。 对于简单请求,基本上设置一个响应头Access-Control-Allow-Origin足矣,不会发探测请求(options)。 而对于复杂请求,往往需要一些额外的响应头的处理,会发探测请求。 那简单请求和复杂请求是如何划分的呢?先看下什么是简单请求:

请求方法为以下3种:

HEAD、GET、POST

请求头为以下3种:

Accept 期望返回格式
Accept-Language 期望返回的语言
Content-Type 决定文件接收方如何解析
其中Content-Type只能是:text/plain、multipart/form-data 或 application/x-www-form-urlencoded
这也就意味着:application/json 不是简单请求

除此之外的,都视为复杂请求

options

只有复杂请求会发送options请求

可使用Access-Control-Max-Age 设置options请求发送时间间隔 Access-Control-Max-Age: 600 (10分钟)
Access-Control-Max-Age表示Access-Control-Allow-Origin和Access-Control-Allow-Headers的缓存时长)
在 Firefox 中,上限是24小时 (即 86400 秒)。)
在 Chromium v76 之前, 上限是 10 分钟(即 600 秒)。)
从 Chromium v76 开始,上限是 2 小时(即 7200 秒)。)
Chromium 同时规定了一个默认值 5 秒。)
如果值为 -1,表示禁用缓存,则每次请求前都需要使用 OPTIONS 预检请求。

复杂请求的限制

对于复杂请求限制主要体现在两个方面:方法限制和请求头限制
对于前者,后端可通过设置Access-Control-Allow-Methods,允许指定方法跨域,多个值则用逗号隔开 'PUT,DELETE'
对于后者,后端可通过设置Access-Control-Allow-Headers,允许指定头跨域,多个值则用逗号隔开 'xxx,yyy'

跨域携带cookie

默认情况下,不论是fetch还是axios,都不会跨域携带cookie。
如果允许携带cookie,那后端设置的Access-Control-Allow-Origin和其他头的值不能是*,要具体指定
如果允许携带cookie,需要后端设置Access-Control-Allow-Credentials为true

fetch默认会忽略cookie的发送

omit:默认值,忽略cookie的发送
same-origin:表示cookie只能同域发送,不能跨域发送
include:既可以同域发送,也可以跨域发送

 fetch('http://localhost:3000/api/',{
            headers:{
                token:'xxx'
            },
            credentials: 'include'
        }).then(res => {
            return res.json()
        }).then(res => {
            console.log(res)
  })

axios默认不允许跨域携带cookie

可通过设置:axios.defaults.withCredentials = true;改变

后端跨域设置

const app = new (require('koa'))
app.use((ctx) => {
   // ctx.set('Access-Control-Allow-Origin', '*')
    ctx.set('Access-Control-Allow-Origin', ctx.headers.origin)
    ctx.set('Access-Control-Allow-Credentials',true)
    // ctx.set('Access-Control-Allow-Headers', '*')
    ctx.set('Access-Control-Allow-Headers', 'token')
    // ctx.set('Access-Control-Allow-Methods', 'PUT,DELETE')
    ctx.set('Access-Control-Allow-Methods', '*')
    ctx.set('Access-Control-Max-Age', 60)//1分钟内不再发options请求
    ctx.set('Set-Cookie', 'token=xxxyyyzzz')
    ctx.body = { name: "tom" }
})

app.listen(3000, () => {
    console.log('run server')
})