[英]Get and Set a Single Cookie with Node.js HTTP Server
我希望能够设置单个 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。
没有获取/设置 cookie 的快速功能访问,所以我想出了以下技巧:
var http = require('http');
function parseCookies (request) {
var list = {},
rc = request.headers.cookie;
rc && rc.split(';').forEach(function( cookie ) {
var parts = cookie.split('=');
list[parts.shift().trim()] = decodeURI(parts.join('='));
});
return list;
}
http.createServer(function (request, response) {
// To Read a Cookie
var 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);
console.log('Server running at http://127.0.0.1:8124/');
这会将所有的cookies存储到cookies对象中,写head时需要设置cookies。
如果您使用 express 库,就像许多 node.js 开发人员所做的那样,有一种更简单的方法。 查看 Express.js 文档页面以获取更多信息。
上面的解析示例有效,但 express 为您提供了一个很好的功能来处理这个问题:
app.use(express.cookieParser());
要设置 cookie:
res.cookie('cookiename', 'cookievalue', { maxAge: 900000, httpOnly: true });
要清除 cookie:
res.clearCookie('cookiename');
RevNoah 给出了最好的答案,建议使用 Express 的cookie parser 。 但是,这个答案现在已经 3 年了,而且已经过时了。
使用Express ,您可以按如下方式读取 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"
},
作为对@Corey Hart 回答的增强,我使用以下代码重写了parseCookies()
:
这是工作示例:
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 模块。 如果 OP 使用的是restify ,他可以使用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);
您可以使用“cookies”npm 模块,该模块具有一组全面的功能。
文档和示例位于:
https://github.com/jed/cookies
要让 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;
};
然后获取一个单独的cookie:
get_cookies(request)['my_cookie']
Cookies通过 HTTP-Headers传输
您只需要解析请求头并放置响应头。
让我重复一下这里的答案忽略的这部分问题:
可以用几行代码完成,而不需要拉入第三方库吗?
Cookie 是从带有Cookie
标头的请求中读取的。 它们只包含name
和value
。 由于路径的工作方式,可以发送多个同名的 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()
是为了避免数组的突变。)
“写入”cookie 是通过在响应中使用Set-Cookie
标头完成的。 response.headers['Set-Cookie']
对象实际上是一个数组,因此您将推送到它。 它接受一个字符串,但具有比name
和value
更多的值。 最难的部分是编写字符串,但这可以在一行中完成。
/**
* @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
标头。 这就是为什么它是一个数组。
如果您决定使用express
、 cookie-parser
或cookie
,请注意它们具有非标准的默认值。 解析的 Cookie 总是 URI 解码(百分比解码)。 这意味着如果您使用具有以下任何字符的名称或值: !#$%&'()*+/:<=>?@[]^`{|}
将在这些库中以不同的方式处理它们。 如果您正在设置 cookie,它们将使用%{HEX}
进行编码。 如果您正在阅读 cookie,则必须对其进行解码。
例如,虽然email=name@domain.com
是一个有效的 cookie,但这些库会将其编码为email=name%40domain.com
。 如果您在 cookie 中使用%
,则解码可能会出现问题。 它会被破坏。 例如,您的 cookie 为: secretagentlevel=50%007and50%006
变为secretagentlevel=507and506
。 这是一个边缘情况,但如果切换库需要注意。
此外,在这些库中,cookie 设置为默认path=/
,这意味着它们会在每个 url 请求上发送到主机。
如果您想自己编码或解码这些值,可以分别使用encodeURIComponent
或decodeURIComponent
。
参考:
附加信息:
这是一个用于在 node.js 中管理 cookie 的简洁的 copy-n-paste 补丁。 为了美观,我将在 CoffeeScript 中执行此操作。
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 安装 cookieParser
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 也很容易。您必须通过调用请求对象的 'cookie' 属性从请求中提取 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
});
});
这是读取cookie并将它们转换为客户端的键值对对象的选项,也可以在服务器端使用它。
注意:如果值中有=
,不用担心。 如果键中有一个=
,天堂里的麻烦。
更多注释:有些人可能会争辩可读性,因此可以根据需要将其分解。
我喜欢注释:添加错误处理程序(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}`)
}
iLikeCookies()
将通过;
( ;
后的空格):
["name=Cookie Monster", "likesCookies=yes=withARandomEquals"]
然后我们映射该数组并使用正则表达式捕获 parens按=
的第一次出现进行拆分:
[["name", "Cookie Monster"], ["likesCookies", "yes=withARandomEquals"]]
然后使用我们的朋友`Object.fromEntries 使其成为key, val 对的对象。
诺斯。
我写了这个简单的函数只是传递req.headers.cookie
和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
}
我知道这个问题已经有很多答案,但这里有一个用原生 JS 制作的 function。
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 字符串。 每个键值对都用分号 (;) 分隔。 因此,第一步是将字符串分成每个键值对。
之后,function 将“=”的第一个实例替换为不在字符串 rest 中的随机字符,对于这个 function,我决定使用 NULL 字符 ( )。 键值对现在可以分成两部分。 这两部分现在可以组合成 JSON。
您可以使用 cookie 库来解析传入的多个 cookies,这样您就不必担心异常情况:-
var cookies = cookie.parse('foo=bar; equation=E%3Dmc%5E2'); // { foo: 'bar', 等式: 'E=mc^2' }
要写一个 cookie,你可以这样做:-
response.writeHead(200, { "Set-Cookie": mycookie=cookie
, "Content-Type": text/plain
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.