fetch() 无法设置从服务器接收到的 cookie?
Posted
技术标签:
【中文标题】fetch() 无法设置从服务器接收到的 cookie?【英文标题】:fetch() cannot set cookies received from the server? 【发布时间】:2017-07-31 07:21:39 【问题描述】:我正在使用 Express.js 服务器。使用cookie-parser
我已经打开了这个端点
app.get("/s", (req,res) =>
res.cookie("bsaSession", req.session.id)
res.send("set cookie ok")
)
当我手动使用浏览器到http://localhost:5555/s
运行网站时,浏览器调试控制台显示cookie 已被应用。
但是当我使用fetch
API 做等效时,它并没有设置cookie。
async trySetCookie()
await fetch("http://localhost:5555/s",
method: 'GET',
credentials: 'same-origin'
)
为什么?
【问题讨论】:
"它没有设置 cookie" --- 你怎么知道的?浏览器是否在请求标头中发送了 cookie? 我查看了 Safari 调试控制台 > 存储 > Cookies。当我单击调用trySetCookie()
的按钮时,列表不会改变。但是当我直接进入该页面时,列表会立即添加新的 cookie。
那么,您在响应标头中看到Set-Cookie
了吗?该脚本是否在同一个端口上运行?
这可能只是 Safari 调试控制台在 Ajax 调用完成后没有立即更新其显示的情况。我建议你用代码测试 cookie 的存在。获取完成后,只需执行console.log(document.cookie)
。
我又找到了一条线索,在这两种情况下Set-Cookie
肯定会显示要设置的cookie,但在fetch
情况下,它总是在cookie 字符串后面有HttpOnly
。这可能是阻止浏览器设置 cookie 的原因?我尝试在服务器端添加httpOnly : false
选项,但fetch
仍然有HttpOnly
无论如何。
【参考方案1】:
我找到了解决方案。这个问题的核心是我触发fetch
的按钮在http://localhost:3000/
上。服务器在http://localhost:5555/
(我在自己的机器上模拟真实环境)
问题是这个fetch
调用
async trySetCookie()
await fetch("http://localhost:5555/s",
method: 'GET',
credentials: 'same-origin'
)
没有credentials
,浏览器无法通过fetch
(https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials)发送或接收cookies
使用credentials
作为same-origin
,我可以在Set-Cookie
响应标头中看到来自服务器的cookie,但浏览器中没有存储任何内容。一件奇怪的事情是,无论我在服务器上的httpOnly : true/false
设置如何,这个响应总是在cookie 字符串之后标记HttpOnly
。在手动使用浏览器到页面做GET请求的情况下,HttpOnly
照常被尊重,并设置cookies。
所以解决方法是将credentials
设置为include
,以允许跨域cookie发送。
async trySetCookie()
await fetch("http://localhost:5555/s",
method: 'GET',
credentials: 'include'
)
此外,在服务器端,您需要手动允许使用新标头的特定来源:
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")
)
不这样做会导致
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))
当然credentials: 'include'
在客户端仍然是必需的。
【讨论】:
对于 CORS 情况下的第一次身份验证,还需要参数 credentials: 'include'。然后浏览器会自动设置服务器返回的cookie。 布拉赫,你是真正的MVP。已经为此苦苦挣扎了一整天。你应该有一个假期来庆祝你的技能。【参考方案2】:5argon 的解决方案对我来说非常棒,但我不得不将 express cors 中的 origin
设置为 true
。所以在后端:
app.use(
cors(
origin: true,
credentials: true,
)
);
在获取中:
fetch("http://localhost:5555/s",
method: 'GET',
credentials: 'include'
)
【讨论】:
警告使用 NextJS 的人:它显然不喜欢 "origin: true" 和 "origin: '*' " 被设置。不过,约翰的答案应该适用于各种用例以上是关于fetch() 无法设置从服务器接收到的 cookie?的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET Core 2.1 MVC - 无法设置从 Web api 响应接收到的 cookie
“无法解析的日期:1302828677828”试图用 Gson 反序列化从服务器接收到的毫秒格式日期
解析ajax服务请求——客户端的数据配置解析——服务端node的接收数据的解析——其他状态——fetch——ajax封装fetch