使用 Node.js HTTP 服务器获取和设置单个 Cookie

我希望能够设置单个 cookie,并在每次向 nodejs 服务器实例发出请求时读取该 cookie。只需要几行代码就可以完成,而不需要引入第三方库吗?

var http = require('http');


http.createServer(function (request, response) {
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end('Hello World\n');
}).listen(8124);


console.log('Server running at http://127.0.0.1:8124/');

只是尝试直接从 nodejs.org 获取上面的代码,并在其中添加 cookie。

386326 次浏览

饼干转移 通过 HTTP 头
您只需要解析请求标头并放置响应标头。

没有快速获取/设置 cookie 的函数访问权限,所以我想出了以下黑客技巧:

const http = require('http');


function parseCookies (request) {
const list = {};
const cookieHeader = request.headers?.cookie;
if (!cookieHeader) return list;


cookieHeader.split(`;`).forEach(function(cookie) {
let [ name, ...rest] = cookie.split(`=`);
name = name?.trim();
if (!name) return;
const value = rest.join(`=`).trim();
if (!value) return;
list[name] = decodeURIComponent(value);
});


return list;
}


const server = http.createServer(function (request, response) {
// To Read a Cookie
const cookies = parseCookies(request);


// To Write a Cookie
response.writeHead(200, {
"Set-Cookie": `mycookie=test`,
"Content-Type": `text/plain`
});


response.end(`Hello World\n`);
}).listen(8124);


const {address, port} = server.address();
console.log(`Server running at http://${address}:${port}`);

这将把所有 cookie 存储到 cookies 对象中,并且在编写头部时需要设置 cookies。

您可以使用“ cookies”npm 模块,该模块具有一组全面的特性。

以下网址的文件和示例:
Https://github.com/jed/cookies

如果您正在使用 Express 库,就像许多 node.js 开发人员所做的那样,有一种更简单的方法。有关更多信息,请查看 Express.js 文档页面。

上面的解析示例可以工作,但 Express 提供了一个很好的函数来处理这个问题:

app.use(express.cookieParser());

设置一个 cookie:

res.cookie('cookiename', 'cookievalue', { maxAge: 900000, httpOnly: true });

清除饼干:

res.clearCookie('cookiename');

这里有一个简洁的复制粘贴补丁,用于管理节点中的 cookie。

http = require 'http'


http.IncomingMessage::getCookie = (name) ->
cookies = {}
this.headers.cookie && this.headers.cookie.split(';').forEach (cookie) ->
parts = cookie.split '='
cookies[parts[0].trim()] = (parts[1] || '').trim()
return


return cookies[name] || null


http.IncomingMessage::getCookies = ->
cookies = {}
this.headers.cookie && this.headers.cookie.split(';').forEach (cookie) ->
parts = cookie.split '='
cookies[parts[0].trim()] = (parts[1] || '').trim()
return


return cookies


http.OutgoingMessage::setCookie = (name, value, exdays, domain, path) ->
cookies = this.getHeader 'Set-Cookie'
if typeof cookies isnt 'object'
cookies = []


exdate = new Date()
exdate.setDate(exdate.getDate() + exdays);
cookieText = name+'='+value+';expires='+exdate.toUTCString()+';'
if domain
cookieText += 'domain='+domain+';'
if path
cookieText += 'path='+path+';'


cookies.push cookieText
this.setHeader 'Set-Cookie', cookies
return

现在你可以像预期的那样处理 cookie 了:

server = http.createServer (request, response) ->
#get individually
cookieValue = request.getCookie 'testCookie'
console.log 'testCookie\'s value is '+cookieValue


#get altogether
allCookies = request.getCookies()
console.log allCookies


#set
response.setCookie 'newCookie', 'cookieValue', 30


response.end 'I luvs da cookies';
return


server.listen 8080
var cookie = 'your_cookie';
var cookie_value;
var i = request.headers.indexOf(cookie+'=');
if (i != -1) {
var eq = i+cookie.length+1;
var end = request.headers.indexOf(';', eq);
cookie_value = request.headers.substring(eq, end == -1 ? undefined : end);
}

要让 Cookie 分割器处理 Cookie 值中包含“ =”的 Cookie,请执行以下操作:

var get_cookies = function(request) {
var cookies = {};
request.headers && request.headers.cookie.split(';').forEach(function(cookie) {
var parts = cookie.match(/(.*?)=(.*)$/)
cookies[ parts[1].trim() ] = (parts[2] || '').trim();
});
return cookies;
};

然后得到一个单独的饼干:

get_cookies(request)['my_cookie']

作为对@Corey Hart 答案的增强,我用以下方法重写了 parseCookies():

  • Exec -使用正则表达式解析“ name = value”字符串

下面是一个实际的例子:

let http = require('http');


function parseCookies(str) {
let rx = /([^;=\s]*)=([^;]*)/g;
let obj = { };
for ( let m ; m = rx.exec(str) ; )
obj[ m[1] ] = decodeURIComponent( m[2] );
return obj;
}


function stringifyCookies(cookies) {
return Object.entries( cookies )
.map( ([k,v]) => k + '=' + encodeURIComponent(v) )
.join( '; ');
}


http.createServer(function ( request, response ) {
let cookies = parseCookies( request.headers.cookie );
console.log( 'Input cookies: ', cookies );
cookies.search = 'google';
if ( cookies.counter )
cookies.counter++;
else
cookies.counter = 1;
console.log( 'Output cookies: ', cookies );
response.writeHead( 200, {
'Set-Cookie': stringifyCookies(cookies),
'Content-Type': 'text/plain'
} );
response.end('Hello World\n');
} ).listen(1234);

我还注意到 OP 使用 http 模块。 如果作业使用的是 重整旗鼓,他可以利用 Restify-cookies:

var CookieParser = require('restify-cookies');
var Restify = require('restify');
var server = Restify.createServer();
server.use(CookieParser.parse);
server.get('/', function(req, res, next){
var cookies = req.cookies; // Gets read-only cookies from the request
res.setCookie('my-new-cookie', 'Hi There'); // Adds a new cookie to the response
res.send(JSON.stringify(cookies));
});
server.listen(8080);

列夫诺亚对此给出了最好的回答,他建议使用 Express 的 Cookie 解析器。但是,这个答案现在已经3岁了,已经过时了。

使用 特快,您可以如下所示读取 cookie

var express = require('express');
var cookieParser = require('cookie-parser');
var app = express();
app.use(cookieParser());
app.get('/myapi', function(req, resp) {
console.log(req.cookies['Your-Cookie-Name-Here']);
})

并用以下代码更新 package.json,替换适当的相对最新的版本。

"dependencies": {
"express": "4.12.3",
"cookie-parser": "1.4.0"
},

这里描述了更多像设置和解析 cookie 这样的操作 < a href = “ https://github.com/Expressjs/cookie-parser”rel = “ norefrer”> 在这里

首先需要创建 cookie (例如,我在 cookie 中包装了令牌) ,然后在 response 中设置它

app.use(cookieParser());

浏览器将它保存在它的“资源”标签,并将用于每一个请求之后采取的初始 URL 作为基础

var token = student.generateToken('authentication');
res.cookie('token', token, {
expires: new Date(Date.now() + 9999999),
httpOnly: false
}).status(200).send();

从服务器端的请求获取 cookie 也很容易。您必须通过调用 request 对象的“ cookie”属性从 request 中提取 cookie。

var token = req.cookies.token; // Retrieving Token stored in cookies

如果您不关心 cookie中的内容,只是想使用它,那么可以使用 request(一个流行的节点模块)尝试这种干净的方法:

var request = require('request');
var j = request.jar();
var request = request.defaults({jar:j});
request('http://www.google.com', function () {
request('http://images.google.com', function (error, response, body){
// this request will will have the cookie which first request received
// do stuff
});
});

使用一些 ES5/6魔法和 RegEx 魔法

这里有一个选项可以读取 Cookie 并将它们转换成一个键的对象,客户端的值对,也可以使用它服务器端。

注意 : 如果值中有 =,不用担心。如果有一个 =在关键,麻烦在天堂。

更多注释 : 有些人可能会争论可读性,所以你可以随意分解它。

I Like Notes : 添加一个错误处理程序(try catch)没有坏处。

const iLikeCookies = () => {
return Object.fromEntries(document.cookie.split('; ').map(v => v.split(/=(.+)/)));
}


const main = () => {
// Add Test Cookies
document.cookie = `name=Cookie Monster;expires=false;domain=localhost`
document.cookie = `likesCookies=yes=withARandomEquals;expires=false;domain=localhost`;


// Show the Objects
console.log(document.cookie)
console.log('The Object:', iLikeCookies())


// Get a value from key
console.log(`Username: ${iLikeCookies().name}`)
console.log(`Enjoys Cookies: ${iLikeCookies().likesCookies}`)
}

enter image description here

发生什么事了?

iLikeCookies()会按 ;(;之后的空间)分割曲奇:

["name=Cookie Monster", "likesCookies=yes=withARandomEquals"]

然后,我们使用 正则表达式捕获括号映射这个数组,并通过首次出现的 =进行分割:

[["name", "Cookie Monster"], ["likesCookies", "yes=withARandomEquals"]]

然后使用我们的朋友‘ Object.from 条目将其设置为 key 对象,val 对。

很好。

我写了这个简单的函数 req.headers.cookie和 < strong > cookie 名称

const getCookieByName =(cookies,name)=>{
const arrOfCookies = cookies.split(' ')
let yourCookie = null


arrOfCookies.forEach(element => {
if(element.includes(name)){
yourCookie = element.replace(name+'=','')
}
});
return yourCookie
}

让我重复这个问题的一部分,这里的答案被忽略了:

只需要几行代码就可以完成,而不需要引入第三方库吗?


读饼干

Cookie 从带有 Cookie头的请求中读取。它们只包括 namevalue。由于路径的工作方式,可以发送多个同名 Cookie。在 NodeJS 中,所有 Cookie 作为一个字符串在 Cookie头中发送。你用 ;把它们分开。一旦有了 cookie,等号左边的所有内容(如果有的话)都是 name,之后的所有内容都是 value。有些浏览器会接受一个没有等号的 cookie,并假定该名称为空。空白不算作 cookie 的一部分。值也可以用双引号(")包装。值还可以包含 =。例如,formula=5+3=8是一个有效的 cookie。

/**
* @param {string} [cookieString='']
* @return {[string,string][]} String Tuple
*/
function getEntriesFromCookie(cookieString = '') {
return cookieString.split(';').map((pair) => {
const indexOfEquals = pair.indexOf('=');
let name;
let value;
if (indexOfEquals === -1) {
name = '';
value = pair.trim();
} else {
name = pair.substr(0, indexOfEquals).trim();
value = pair.substr(indexOfEquals + 1).trim();
}
const firstQuote = value.indexOf('"');
const lastQuote = value.lastIndexOf('"');
if (firstQuote !== -1 && lastQuote !== -1) {
value = value.substring(firstQuote + 1, lastQuote);
}
return [name, value];
});
}


const cookieEntries = getEntriesFromCookie(request.headers.Cookie);
const object = Object.fromEntries(cookieEntries.slice().reverse());

如果您不希望看到重复的名称,那么可以转换为一个对象,这会使事情变得更简单。然后您可以像 object.myCookieName那样访问以获得值。如果需要重复,那么需要遍历 cookieEntries。浏览器以降低优先级的方式提供 Cookie,因此逆向操作可以确保最高优先级的 Cookie 出现在对象中。(.slice()是为了避免数组的变异。)


设置 Cookies

“写”cookie 是通过在响应中使用 Set-Cookie头来完成的。response.headers['Set-Cookie']对象实际上是一个数组,因此您将向它推送。它接受一个字符串,但是比 namevalue有更多的值。最困难的部分是编写字符串,但这可以在一行中完成。

/**
* @param {Object} options
* @param {string} [options.name='']
* @param {string} [options.value='']
* @param {Date} [options.expires]
* @param {number} [options.maxAge]
* @param {string} [options.domain]
* @param {string} [options.path]
* @param {boolean} [options.secure]
* @param {boolean} [options.httpOnly]
* @param {'Strict'|'Lax'|'None'} [options.sameSite]
* @return {string}
*/
function createSetCookie(options) {
return (`${options.name || ''}=${options.value || ''}`)
+ (options.expires != null ? `; Expires=${options.expires.toUTCString()}` : '')
+ (options.maxAge != null ? `; Max-Age=${options.maxAge}` : '')
+ (options.domain != null ? `; Domain=${options.domain}` : '')
+ (options.path != null ? `; Path=${options.path}` : '')
+ (options.secure ? '; Secure' : '')
+ (options.httpOnly ? '; HttpOnly' : '')
+ (options.sameSite != null ? `; SameSite=${options.sameSite}` : '');
}


const newCookie = createSetCookie({
name: 'cookieName',
value: 'cookieValue',
path:'/',
});
response.headers['Set-Cookie'].push(newCookie);

请记住,您可以设置多个 cookie,因为您实际上可以在请求中设置多个 Set-Cookie标头。这就是为什么它是一个数组。


关于外部图书馆的说明:

如果您决定使用 expresscookie-parsercookie,请注意它们的默认值是非标准的。已解析的 Cookie 始终是 URI 解码(百分比解码)。这意味着,如果您使用的名称或值具有以下任何一个字符: !#$%&'()*+/:<=>?@[]^`{|},则它们将与这些库进行不同的处理。如果您正在设置 cookie,它们是用 %{HEX}编码的。如果你在读一个饼干,你必须解码它们。

例如,虽然 email=name@domain.com是一个有效的 cookie,但是这些库将它编码为 email=name%40domain.com。如果在 cookie 中使用 %,则解码可能会出现问题。会弄坏的。例如,原来是: secretagentlevel=50%007and50%006的 cookie 变成了 secretagentlevel=507and506。这是一个边缘情况,但是如果切换库,有些事情需要注意。

而且,在这些库中,cookie 设置为默认的 path=/,这意味着它们在每次发送到主机的 URL 请求时都会被发送。

如果您想自己对这些值进行编码或解码,则可以分别使用 encodeURIComponentdecodeURIComponent


参考文献:


附加信息:

我知道这个问题已经有很多答案了,但是这里有一个用本地 JS 编写的函数。

function parseCookies(cookieHeader) {
var cookies = {};
cookieHeader
.split(";")
.map(str => str.replace("=", "\u0000")
.split("\u0000"))
.forEach(x => cookies[x[0]] = x[1]);


return cookies;
}

它从接受 document.cookie 字符串开始。每个键值对由分号(;)分隔。因此,第一步是将字符串划分为每个键-值对。

然后,该函数用字符串其余部分中没有的随机字符替换“ =”的第一个实例,对于这个函数,我决定使用 NULL 字符(u0000)。键值对现在可以分成两部分。这两部分现在可以组合成 JSON。