javascript - Získání a nastavení jediné cookie pomocí Node.js HTTP serveru
Chci být schopen nastavit jednu cookie a číst tuto jedinou cookie při každém požadavku odeslaném na instanci serveru Node.js. Lze to provést v několika řádcích kódu, bez potřeby přidávat knihovnu třetí strany?
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/');
Jen se snažím vzít výše uvedený kód přímo z nodejs.org a začlenit do něj cookie.
Odpověď č. 1
Neexistuje rychlý způsob přístupu k získávání/nastavování cookies, takže jsem přišel s následujícím trikem:
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}`);
Toto uloží všechny cookies do objektu cookies a musíte nastavit cookies, když zapisujete hlavičku.
Odpověď č. 2
Pokud používáte knihovnu express, jako to dělá mnoho vývojářů node.js, existuje jednodušší způsob. Pro více informací si prohlédněte stránku dokumentace Express.js.
Příklad parsování výše funguje, ale Express vám poskytuje pěknou funkci, která se o to postará:
app.use(express.cookieParser());
Chcete-li nastavit cookie:
res.cookie('cookiename', 'cookievalue', { maxAge: 900000, httpOnly: true });
Pro vyčištění sušenky:
res.clearCookie('cookiename');
Odpověď č. 3
RevNoah měl nejlepší odpověď s návrhem použít Expressův parser cookie. Ale tato odpověď je nyní stará 3 roky a je zastaralá.
Pomocí Expressu můžete přečíst cookie následujícím způsobem
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']);
})
A aktualizujte svůj package.json následujícím způsobem, přičemž nahraďte příslušnými relativně nejnovějšími verzemi.
"dependencies": {
"express": "4.12.3",
"cookie-parser": "1.4.0"
},
Další operace, jako je nastavování a zpracovávání cookies, jsou popsány zde a zde
Odpověď č. 4
Jako rozšíření odpovědi @Corey Harta jsem přepsal parseCookies() pomocí:
- RegExp.prototype.exec - použijte regulární výraz k analýze řetězců „name=value“
Zde je fungující příklad:
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);
Také si všímám, že autor příspěvku používá modul http. Pokud by autor příspěvku používal restify, může využít 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);
Odpověď č. 5
Dovolte mi zopakovat tuto část otázky, kterou zde odpovědi ignorují:
Lze to udělat v několika řádcích kódu, bez potřeby přidávat knihovnu třetí strany?
Čtení cookies
Cookies jsou čteny z požadavků přes hlavičku Cookie. Obsahují pouze name a value. Kvůli tomu, jak fungují cesty, mohou být odeslány více cookies se stejným názvem. V NodeJS jsou všechny cookies spojeny do jednoho řetězce, jak jsou odesílány v hlavičce Cookie. Rozdělíte je pomocí ;. Jakmile máte cookie, všechno nalevo od rovná se (pokud je přítomno) je name a všechno napravo je value. Některé prohlížeče přijmou cookie bez rovnítka a předpokládají, že název je prázdný. Mezery se nepočítají jako součást cookie. Hodnoty mohou být také uzavřeny v uvozovkách ("). Hodnoty mohou také obsahovat =. Například formula=5+3=8 je platná 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());
Pokud neočekáváte duplicitní názvy, pak můžete převést na objekt, což věci usnadní. Pak můžete přistupovat například takto object.myCookieName pro získání hodnoty. Pokud očekáváte duplicity, budete chtít iterovat přes cookieEntries. Prohlížeče poskytují cookies v sestupném pořadí podle priority, takže obrácení zajistí, že cookie s nejvyšší prioritou se objeví v objektu. (Použití .slice() je k tomu, aby nedošlo k mutaci pole.)
Nastavení cookies
"Zapisování" cookies se provádí pomocí hlavičky Set-Cookie ve vaší odpovědi. Objekt response.headers['Set-Cookie'] je ve skutečnosti pole, takže do něj budete přidávat položky. Přijímá řetězec, ale obsahuje více hodnot než jen name a value. Nejtěžší částí je napsat řetězec, ale lze to provést v jednom řádku.
/**
* @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);
Pamatujte, že můžete nastavit více cookies, protože ve skutečnosti můžete ve svém požadavku nastavit více hlaviček Set-Cookie. Proto je to pole.
Poznámka k externím knihovnám:
Pokud se rozhodnete používat express, cookie-parser nebo cookie, vezměte na vědomí, že mají výchozí hodnoty, které nejsou standardní. Cookies, které jsou analyzovány, jsou vždy dekódovány URI (percentuálně dekódovány). To znamená, že pokud použijete název nebo hodnotu, která obsahuje některý z následujících znaků: !#$%&'()*+/:<=>?@[]^`{|}, budou s těmito knihovnami zpracovány odlišně. Pokud nastavujete cookies, jsou zakódovány pomocí %{HEX}. A pokud čtete cookie, musíte je dekódovat.
Například, zatímco [email je platné cookie, tyto knihovny jej zakódují jako email=name%40domain.com. Dekódování může vykazovat problémy, pokud ve svém cookie používáte %. Bude poškozeno. Například vaše cookie, které bylo: secretagentlevel=50%007and50%006, se změní na secretagentlevel=507and506. To je okrajový případ, ale je to něco, co je třeba mít na paměti při přechodu na jiné knihovny.
Také tyto knihovny nastavují cookies s výchozí hodnotou path=/, což znamená, že jsou odesílány při každém požadavku na URL hostitele.
Pokud tyto hodnoty chcete kódovat nebo dekódovat sami, můžete použít encodeURIComponent nebo decodeURIComponent.
Reference:
- Syntaxe cookies
- Syntaxe Set-Cookie
Další informace:
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cookie
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
