fetch()无法设置从服务器接收的cookie?

5ar*_*gon 2 javascript cookies session-cookies node.js express

我正在使用Express.js服务器。随着cookie-parser我打开这个端点

app.get("/s", (req,res) => {
    res.cookie("bsaSession", req.session.id)
    res.send("set cookie ok")
})
Run Code Online (Sandbox Code Playgroud)

当我手动使用浏览器http://localhost:5555/s访问运行浏览器的网站时,调试控制台将显示cookie已被应用。

在此处输入图片说明

但是,当我使用fetchAPI执行等效操作时,它不会设置Cookie。

  async trySetCookie()
  {
    await fetch("http://localhost:5555/s",{
       method: 'GET',
       credentials: 'same-origin'
    })
  }
Run Code Online (Sandbox Code Playgroud)

为什么?

5ar*_*gon 5

我找到了解决方案。这个问题的核心是我的按钮触发fetchon http://localhost:3000/。服务器已打开http://localhost:5555/(我正在自己的计算机上模拟真实环境)

问题是这个fetch电话

  async trySetCookie()
  {
    await fetch("http://localhost:5555/s",{
       method: 'GET',
       credentials: 'same-origin'
    })
  }
Run Code Online (Sandbox Code Playgroud)

没有credentials,浏览器将无法通过fetchhttps://developer.mozilla.org/en-US/docs/Web/API/Request/credentials)发送或接收Cookie。

随着credentials作为same-origin我能看到饼干从该服务器的Set-Cookie响应头,但没有被存储在浏览器中。一件奇怪的事是,HttpOnly无论我{httpOnly : true/false}在服务器上的设置如何,此响应始终在cookie字符串之后进行标记。在手动使用浏览器对页面进行GET请求的情况下,HttpOnly照常被尊重,并设置了cookie。

因此,解决方案是将其设置credentialsinclude允许跨域Cookie发送。

  async trySetCookie()
  {
    await fetch("http://localhost:5555/s",{
       method: 'GET',
       credentials: 'include'
    })
  }
Run Code Online (Sandbox Code Playgroud)

另外,在服务器端,您需要手动允许带有新标头的特定来源:

app.get("/s", (req,res) => {
    res.cookie("bsaSession", req.session.id, {httpOnly:false})
    res.header('Access-Control-Allow-Origin', 'http://localhost:3000')
    res.header('Access-Control-Allow-Credentials','true'
    res.send("set")
})
Run Code Online (Sandbox Code Playgroud)

不这样做会导致

XMLHttpRequest cannot load http://localhost:5555/s. Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true.

但是无论该错误如何,都将设置cookie。包含该标头以使错误保持静音仍然很不错。

如果您正在使用cors中间件,Express则更加容易。您可以使用这些选项

var corsOptions = {
  origin: 'http://localhost:3000',
  credentials:  true
}

app.use(cors(corsOptions))
Run Code Online (Sandbox Code Playgroud)

当然credentials: 'include',客户端仍然需要。

  • 对于 CORS 情况下的第一次身份验证,还需要参数 {credentials: 'include'}。然后浏览器会自动设置服务器返回的cookie。 (2认同)