Node.js中如何为HTTP2请求实现Cookie Jar(Cookie容器)
Node.js的内置http2模块确实没有像一些封装好的HTTP客户端那样自带Cookie容器功能,不过我们可以通过两种方式解决跨请求的Cookie会话问题:手动实现Cookie的存储与携带,或者借助第三方库简化操作。
方法一:手动实现Cookie管理
如果不想依赖第三方库,我们可以自己维护Cookie存储,解析响应的Set-Cookie头,并在后续请求中拼接Cookie头发送。
步骤1:编写Cookie解析与存储工具
先创建一个Cookie存储对象,再实现解析Set-Cookie和生成请求Cookie头的函数:
const http2 = require('http2'); // 存储Cookie的结构:{ 域名: { 路径: { Cookie名: { 值, 过期时间, 其他属性 } } } } const cookieStore = {}; // 解析响应头中的Set-Cookie,存入存储对象 function parseSetCookie(setCookieHeader, requestDomain) { if (!setCookieHeader) return; const cookieStrList = Array.isArray(setCookieHeader) ? setCookieHeader : [setCookieHeader]; cookieStrList.forEach(cookieStr => { const parts = cookieStr.split(';').map(item => item.trim()); const [nameValuePair] = parts; const [name, value] = nameValuePair.split('=').map(item => item.trim()); // 解析Cookie的附加属性(domain、path、expires等) const cookieProps = {}; parts.slice(1).forEach(prop => { if (prop.startsWith('domain=')) { cookieProps.domain = prop.split('=')[1].trim(); } else if (prop.startsWith('path=')) { cookieProps.path = prop.split('=')[1].trim(); } else if (prop.startsWith('expires=')) { cookieProps.expires = new Date(prop.split('=')[1].trim()); } else if (prop === 'HttpOnly' || prop === 'Secure') { cookieProps[prop.toLowerCase()] = true; } }); // 确定Cookie的目标域名和路径(没有指定则用当前请求的域名和根路径) const targetDomain = cookieProps.domain || requestDomain.replace(/^https?:\/\//, ''); const targetPath = cookieProps.path || '/'; // 初始化存储结构 if (!cookieStore[targetDomain]) cookieStore[targetDomain] = {}; if (!cookieStore[targetDomain][targetPath]) cookieStore[targetDomain][targetPath] = {}; // 存入Cookie cookieStore[targetDomain][targetPath][name] = { value, ...cookieProps }; }); } // 根据当前请求的域名和路径,生成符合要求的Cookie头字符串 function getRequestCookieHeader(requestDomain, requestPath) { const validCookies = []; const cleanDomain = requestDomain.replace(/^https?:\/\//, ''); // 遍历所有匹配的域名(包括父域名) Object.keys(cookieStore).forEach(storeDomain => { if (cleanDomain.endsWith(storeDomain)) { Object.keys(cookieStore[storeDomain]).forEach(storePath => { // 匹配路径(当前请求路径以Cookie的路径开头) if (requestPath.startsWith(storePath)) { Object.keys(cookieStore[storeDomain][storePath]).forEach(name => { const cookie = cookieStore[storeDomain][storePath][name]; // 跳过已过期的Cookie if (cookie.expires && cookie.expires < new Date()) { delete cookieStore[storeDomain][storePath][name]; return; } validCookies.push(`${name}=${cookie.value}`); }); } }); } }); return validCookies.join('; '); }
步骤2:集成到请求流程中
基于你的原请求代码,加入Cookie管理逻辑,实现跨请求携带会话:
// 第一次请求:获取并存储Cookie function sendFirstRequest() { const client = http2.connect('https://twitter.com'); const req = client.request({ ':method': 'GET', ':path': '/' }); req.setEncoding("utf8"); let body = ""; req.on('response', (responseHeaders) => { // 解析响应的Set-Cookie头,存入存储对象 parseSetCookie(responseHeaders['set-cookie'], 'https://twitter.com'); }); req.on('data', (chunk) => { body += chunk; }); req.on('end', () => { console.log('第一次请求完成,已存储会话Cookie'); client.destroy(); // 发起第二次请求,携带Cookie sendSecondRequest(); }); req.end(); } // 第二次请求:携带存储的Cookie function sendSecondRequest() { const client = http2.connect('https://twitter.com'); // 获取当前请求对应的Cookie头 const cookieHeader = getRequestCookieHeader('https://twitter.com', '/home'); const req = client.request({ ':method': 'GET', ':path': '/home', 'cookie': cookieHeader // 携带Cookie头 }); req.setEncoding("utf8"); let body = ""; req.on('data', (chunk) => { body += chunk; }); req.on('end', () => { console.log('第二次请求响应内容:', body); client.destroy(); }); req.end(); } // 启动请求流程 sendFirstRequest();
方法二:使用第三方Cookie管理库
如果觉得手动实现太繁琐,可以用成熟的第三方库简化操作,比如轻量级的cookiejar库。
步骤1:安装依赖
npm install cookiejar
步骤2:集成到HTTP/2请求中
const http2 = require('http2'); const { CookieJar, Cookie } = require('cookiejar'); // 创建CookieJar实例,用于管理Cookie const cookieJar = new CookieJar(); // 第一次请求:获取并存储Cookie function sendFirstRequest() { const client = http2.connect('https://twitter.com'); const req = client.request({ ':method': 'GET', ':path': '/' }); req.setEncoding("utf8"); let body = ""; req.on('response', (responseHeaders) => { // 解析Set-Cookie并存入CookieJar const setCookieHeaders = responseHeaders['set-cookie']; if (setCookieHeaders) { const cookieStrList = Array.isArray(setCookieHeaders) ? setCookieHeaders : [setCookieHeaders]; cookieStrList.forEach(cookieStr => { cookieJar.setCookie(Cookie.parse(cookieStr), 'https://twitter.com'); }); } }); req.on('data', (chunk) => { body += chunk; }); req.on('end', () => { console.log('第一次请求完成'); client.destroy(); sendSecondRequest(); }); req.end(); } // 第二次请求:从CookieJar获取并携带Cookie function sendSecondRequest() { const client = http2.connect('https://twitter.com'); // 获取当前请求对应的Cookie字符串 const cookieHeader = cookieJar.getCookieString('https://twitter.com'); const req = client.request({ ':method': 'GET', ':path': '/home', 'cookie': cookieHeader }); req.setEncoding("utf8"); let body = ""; req.on('data', (chunk) => { body += chunk; }); req.on('end', () => { console.log('第二次请求响应内容:', body); client.destroy(); }); req.end(); } sendFirstRequest();
小提示:HTTP/2的:authority头对应HTTP/1.1的Host头,解析Cookie域名时,可以用responseHeaders[':authority']替代手动处理的URL域名,结果会更准确。
内容的提问来源于stack exchange,提问作者James Morgan
相关产品推荐
相关产品推荐

