Fetch API Cookie 问题

前不久做一个项目的时候,全程需要用到 cookie 标识会话身份。网络请求用的 Fetch 可发现一直带不上 cookie。翻阅 Fetch Standard 才寻求到了答案。

A request has an associated credentials mode, which is "omit", "same-origin", or "include". Unless stated otherwise, it is "omit".

Request’s credentials mode controls the flow of credentials during a fetch. Credentials are HTTP cookies, TLS client certificates, and authentication entries. When request’s mode is "navigate", its credentials mode is assumed to be "include" and fetch does not currently account for other values. If HTML changes here, this standard will need corresponding changes.

好嘛,Fetch 默认 credentials: 'omit'。 那我们吧参数改成 include 就万事大吉了。

// GET

fetch(`${root}/api/xxx`, {  
  credentials: 'include'
})
  .then((res) => {
    res.json()
  })
  .then((json) => {
    // do something
  })


// POST

fetch(`${root}/api/xxx`, {  
  credentials: 'include',
  method: 'POST',
  body: data
})
  .then((res) => {
    res.json()
  })
  .then((json) => {
    // do something
  })

以前用 XMLHttpRequest 需要这么设置 credentials,现如今,Fetch 的设置更加方便。

var client = new XMLHttpRequest()  
client.open("GET", "./")  
client.withCredentials = true  

至于为什么 Fetch API 不带 cookie 一起飞,具体原因官方文档也有描述。

When request’s credentials mode is "include" it has an impact on the functioning of the CORS protocol other than including credentials in the fetch.

将 credentials 模式设置为 "include" 虽然能让请求包含 HTTP cookies TLS client certificatesauthentication entries 这些内容,但它会影响到 CORS 协议的功能。

A request’s credentials mode is not necessarily observable on the server; only when credentials exist for a request can it be observed by virtue of the credentials being included. Note that even so, a CORS-preflight request never includes credentials.

请求的 credentials 模式没有必要对服务器可见,只有当 credentials 存在的时候才让服务器知晓。即便如此,CORS 预请求不会带上 credentials

The server developer therefore needs to decide whether or not responses "tainted" with credentials can be shared. And also needs to decide if requests necessitating a CORS-preflight request can include credentials. Generally speaking, both sharing responses and allowing requests with credentials is rather unsafe, and extreme care has to be taken to avoid the confused deputy problem.

开发人员应该自主决定是否确定要在请求内代上 credentials。总之,无论是分发 responses 还是响应 requests,要带上 credentials 都是不安全的,开发人员需要非常注意这一点以避开这个派生问题。