javascript - Ein einzelnes Cookie mit Node.js HTTP-Server abrufen und setzen
Ich möchte in der Lage sein, ein einzelnes Cookie zu setzen und dieses einzelne Cookie bei jeder Anfrage an die Node.js-Serverinstanz zu lesen. Kann das in ein paar Zeilen Code gemacht werden, ohne dass eine Drittanbieter-Bibliothek eingebunden werden muss?
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/');
Ich versuche nur, den obigen Code direkt von nodejs.org zu nehmen und ein Cookie einzubauen.
Antwort #1
Es gibt keinen schnellen Funktionszugriff zum Abrufen/Setzen von Cookies, also habe ich den folgenden Trick entwickelt:
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}`);
Dies wird alle Cookies in das Cookies-Objekt speichern, und Sie müssen Cookies setzen, wenn Sie den Header schreiben.
Antwort #2
Wenn Sie die Express-Bibliothek verwenden, wie viele Node.js-Entwickler, gibt es einen einfacheren Weg. Überprüfen Sie die Express.js-Dokumentationsseite für weitere Informationen.
Das obige Parsing-Beispiel funktioniert, aber Express bietet Ihnen eine nette Funktion, um sich darum zu kümmern:
app.use(express.cookieParser());
Um einen Cookie zu setzen:
res.cookie('cookiename', 'cookievalue', { maxAge: 900000, httpOnly: true });
Um den Cookie zu löschen:
res.clearCookie('cookiename');
Antwort #3
RevNoah hatte die beste Antwort mit dem Vorschlag, den Cookie-Parser von Express zu verwenden. Aber diese Antwort ist jetzt 3 Jahre alt und veraltet.
Mit Express können Sie ein Cookie wie folgt auslesen
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']);
})
Und aktualisieren Sie Ihre package.json wie folgt, indem Sie die entsprechenden relativ neuen Versionen einsetzen.
"dependencies": {
"express": "4.12.3",
"cookie-parser": "1.4.0"
},
Weitere Operationen wie das Setzen und Parsen von Cookies werden hier und hier beschrieben
Antwort #4
Als Ergänzung zu @Corey Harts Antwort habe ich die parseCookies() wie folgt neu geschrieben:
- RegExp.prototype.exec - Regex verwenden, um "name=value"-Strings zu parsen
Hier ist das funktionierende Beispiel:
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);
Ich stelle auch fest, dass der OP das http-Modul verwendet. Wenn der OP restify verwendet hätte, könnte er restify-cookies nutzen:
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);
Antwort #5
Lassen Sie mich diesen Teil der Frage wiederholen, den die Antworten hier ignorieren:
Kann es in wenigen Codezeilen erledigt werden, ohne dass eine Drittanbieter-Bibliothek eingebunden werden muss?
Cookies lesen
Cookies werden aus Anfragen mit dem Cookie-Header gelesen. Sie enthalten nur einen name und einen value. Aufgrund der Funktionsweise von Pfaden können mehrere Cookies mit demselben Namen gesendet werden. In NodeJS werden alle Cookies in einem String zusammengefasst, so wie sie im Cookie-Header gesendet werden. Sie werden mit ; getrennt. Sobald Sie ein Cookie haben, ist alles links vom Gleichheitszeichen (falls vorhanden) der name, und alles danach der value. Einige Browser akzeptieren ein Cookie ohne Gleichheitszeichen und nehmen an, dass der Name leer ist. Leerzeichen zählen nicht zum Cookie. Werte können auch in doppelte Anführungszeichen (") eingeschlossen werden. Werte können auch = enthalten. Zum Beispiel ist formula=5+3=8 ein gültiges 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());
Wenn Sie keine doppelten Namen erwarten, können Sie in ein Objekt konvertieren, was die Sache erleichtert. Dann können Sie darauf zugreifen wie object.myCookieName, um den Wert zu erhalten. Wenn Sie Duplikate erwarten, sollten Sie durch cookieEntries iterieren. Browser liefern Cookies in absteigender Priorität, daher stellt das Umkehren sicher, dass das Cookie mit der höchsten Priorität im Objekt erscheint. (Das .slice() dient dazu, die Mutation des Arrays zu vermeiden.)
Einstellungen Cookies
"Schreiben" von Cookies erfolgt durch die Verwendung des Set-Cookie-Headers in Ihrer Antwort. Das Objekt response.headers['Set-Cookie'] ist tatsächlich ein Array, also musst du darauf pushen. Es akzeptiert eine Zeichenkette, hat aber mehr Werte als nur Name und Value. Der schwierigste Teil ist das Schreiben der Saite, aber das kann man in einer Zeile machen.
/**
* @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);
Denken Sie daran, dass Sie mehrere Cookies setzen können, da Sie tatsächlich mehrere Set-Cookie-Header in Ihrer Anfrage setzen können. Deshalb ist es ein Array.
Hinweis zu externen Bibliotheken:
Wenn Sie sich entscheiden, express, cookie-parser oder cookie zu verwenden, beachten Sie, dass sie Standardeinstellungen haben, die nicht standardmäßig sind. Geparste Cookies werden immer URI-dekodiert (Prozent-dekodiert). Das bedeutet, wenn Sie einen Namen oder Wert verwenden, der eines der folgenden Zeichen enthält: !#$%&'()*+/:<=>?@[]^`{|}, werden diese mit diesen Bibliotheken anders behandelt. Wenn Sie Cookies setzen, werden sie mit %{HEX} kodiert. Und wenn Sie ein Cookie lesen, müssen Sie es dekodieren.
Zum Beispiel, während [email ein gültiger Cookie ist, werden diese Bibliotheken ihn als email=name%40domain.com kodieren. Das Dekodieren kann Probleme zeigen, wenn Sie das % in Ihrem Cookie verwenden. Es wird zerstört. Zum Beispiel wird Ihr Cookie, das war: secretagentlevel=50%007and50%006, zu secretagentlevel=507and506. Das ist ein Grenzfall, aber etwas, das man beachten sollte, wenn man Bibliotheken wechselt.
Außerdem werden bei diesen Bibliotheken Cookies mit einem Standard-path=/ gesetzt, was bedeutet, dass sie bei jeder URL-Anfrage an den Host gesendet werden.
Wenn Sie diese Werte selbst codieren oder decodieren möchten, können Sie jeweils encodeURIComponent oder decodeURIComponent verwenden.
Referenzen:
- Cookie-Syntax
- Set-Cookie-Syntax
Zusätzliche Informationen:
- https://developer.mozilla.org/de/docs/Web/HTTP/Headers/Cookie
- https://developer.mozilla.org/de/docs/Web/HTTP/Headers/Set-Cookie
