Node.js v20中global fetch无法获取Cookie的问题求助
问题场景
有一个端点会设置Cookie后重定向到Cookie列表页面:https://httpbin.org/cookies/set/king/cole
- 浏览器访问该链接,返回预期结果:
{ "cookies": { "king": "cole" } }
- 浏览器控制台执行fetch代码,同样得到预期结果:
const res = await fetch('https://httpbin.org/cookies/set/king/cole') await res.json() // -> { cookies: { king: "cole" }}
- 但在Node.js v20.12.0环境中执行相同代码,返回的Cookie集合为空:
// Welcome to Node.js v20.12.0. // Type ".help" for more information. const res = await fetch('https://httpbin.org/cookies/set/king/cole') await res.json() // -> { cookies: {} }
即使添加credentials: 'include'参数也无效,且该参数在浏览器中本不是必需项。
问题原因
Node.js内置的fetch(底层基于undici库)和浏览器的Cookie处理逻辑存在核心差异:
- 浏览器会自动维护全局CookieJar,重定向过程中自动保存并携带Cookie;
- Node.js默认
fetch不会持久化Cookie,重定向时不会将前一步设置的Cookie传递到目标页面; credentials: 'include'仅控制跨域请求是否携带Cookie,但不负责Cookie的存储与后续携带,因此添加后无法解决问题。
解决方法
方法1:用undici的CookieJar手动管理Cookie
直接利用Node.js fetch底层依赖的undici库提供的CookieJar来实现Cookie持久化:
import { fetch, CookieJar } from 'undici'; const cookieJar = new CookieJar(); const res = await fetch('https://httpbin.org/cookies/set/king/cole', { dispatcher: new fetch.Dispatcher({ cookieJar }) }); const data = await res.json(); console.log(data); // -> { cookies: { king: "cole" }}
方法2:手动提取并重定向时携带Cookie
无需额外依赖,手动从响应头提取Cookie后在重定向请求中携带:
async function fetchWithCookie(url) { let res = await fetch(url, { redirect: 'manual' }); // 提取响应头中的Cookie const setCookie = res.headers.get('set-cookie'); if (res.status === 302 && setCookie) { // 获取重定向目标地址 const redirectUrl = res.headers.get('location'); // 携带Cookie发起请求,仅保留键值对部分 res = await fetch(redirectUrl, { headers: { Cookie: setCookie.split(';')[0] } }); } return res.json(); } // 使用示例 const data = await fetchWithCookie('https://httpbin.org/cookies/set/king/cole'); console.log(data); // -> { cookies: { king: "cole" }}
方法3:使用node-fetch库替代内置fetch
安装带Cookie支持的node-fetch及配套库:
npm install node-fetch@3 tough-cookie fetch-cookie
编写代码实现Cookie持久化:
import fetch from 'node-fetch'; import { CookieJar } from 'tough-cookie'; import { wrapper } from 'fetch-cookie/node-fetch'; const cookieJar = new CookieJar(); const fetchWithCookie = wrapper(fetch, cookieJar); const res = await fetchWithCookie('https://httpbin.org/cookies/set/king/cole'); const data = await res.json(); console.log(data); // -> { cookies: { king: "cole" }}
内容的提问来源于stack exchange,提问作者Monkey Boson
相关产品推荐
相关产品推荐

