Abrufen und Setzen eines einzelnen Cookies mit dem HTTP-Server von Node.js.

159

Ich möchte in der Lage sein, ein einzelnes Cookie zu setzen und dieses einzelne Cookie bei jeder Anforderung an die Serverinstanz von nodejs zu lesen. Kann dies in wenigen Codezeilen erfolgen, ohne dass eine Drittanbieter-Bibliothek abgerufen 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/');

Versuchen Sie einfach, den obigen Code direkt von nodejs.org zu übernehmen und ein Cookie darin zu verarbeiten.

Corey Hart
quelle

Antworten:

190

Es gibt keinen schnellen Funktionszugriff zum Abrufen / Setzen von Cookies, daher habe ich mir den folgenden Hack ausgedacht:

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/');

Dadurch werden alle Cookies im Cookies-Objekt gespeichert, und Sie müssen beim Schreiben des Kopfes Cookies setzen.

Corey Hart
quelle
11
Der obige Code funktioniert nicht richtig, wenn der Wert eines Cookies ein Gleichheitszeichen ( =) wie in einem der Facebook-Cookies wie enthält fbm_1234123412341234=base_domain=.domain.com.
Auge
3
Müssen Cookie-Werte nicht URL-codiert / Prozent codiert sein? = im doockie Wert wäre in diesem Fall ungültig, oder?
Les2
2
In diesem Fall bis ;dahin durch die erste Instanz von aufgeteilt =. Links ist der Schlüssel, rechts ist der Wert.
iLoch
4
Ich stieß auf das gleiche Problem wie @Eye, anstatt die Route von @iLoch zu gehen, wechselte ich parts[0]zu parts.shift()und parts[1]zuparts.join('=')
aron.duby
3
Der angegebene Code hatte schwerwiegende Fehler und die Leute kopierten ihn weiter. Siehe mein letztes Update
Dan
124

Wenn Sie die Express-Bibliothek verwenden, wie es viele Entwickler von node.js tun, gibt es einen einfacheren Weg. Weitere Informationen finden Sie auf der Dokumentationsseite von Express.js.

Das obige Parsing-Beispiel funktioniert, aber Express bietet Ihnen eine nette Funktion, um dies zu erledigen:

app.use(express.cookieParser());

So setzen Sie ein Cookie:

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

So löschen Sie den Cookie:

res.clearCookie('cookiename');
RevNoah
quelle
14
Die Cookie-Bibliothek stammt tatsächlich aus der zugrunde liegenden Bibliotheksverbindung. Sie müssen nicht den gesamten Express nehmen, um einen Cookie-Helfer zu erhalten.
Ajax
1
Tatsächlich
10
cookie-parserist nicht mehr Teil von Express und / oder Connect, sondern als Middleware verfügbar: github.com/expressjs/cookie-parser
Koen.
7
Wie "bekommt" man in diesem Beispiel einen Cookie? Der Vollständigkeit halber und Beantwortung der Frage.
Hubatish
1
Downvoting aufgrund der Notwendigkeit, Express zu installieren, nur um Cookies zu verwenden
Steven
34

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 lesen

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.jsonmit den folgenden, indem Sie die entsprechenden relativ neuesten Versionen ersetzen.

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

Weitere Vorgänge wie das Setzen und Parsen von Cookies werden hier und hier beschrieben

Kirby
quelle
8
Die Frage fragt, wie man bekommt und setzt. Um dies einzustellen, verwenden Sie Folgendes:res.cookie('cookieName', cookieValue, { maxAge: 900000, httpOnly: true });
Augie Gardner
Können Sie Cookies pro Sitzung setzen und erhalten (ohne dass Sie die Schlüssel kennen und damit umgehen müssen)?
Matej J
12

Als Erweiterung der Antwort von @Corey Hart habe ich Folgendes parseCookies()verwendet:

Hier ist das Arbeitsbeispiel:

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 das OP das http-Modul verwendet. Wenn das OP restify verwendet hat , kann er restify-Cookies verwenden :

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);
Stephen Quan
quelle
1
Einige Vorschläge jetzt, 3,5 Jahre später, für zukünftige Zuschauer. Verwenden Sie let/constund stringifyCookieskönnen Sie mit einem ausgekleidet sein, mapanstatt auf diese Weise ein Array zu erstellen .
Ascherer
10

Sie können das npm-Modul "Cookies" verwenden, das über umfassende Funktionen verfügt.

Dokumentation und Beispiele unter:
https://github.com/jed/cookies

zah
quelle
1
Es sieht so aus, als ob dieses Modul für die Verwendung in http-Servern vorgesehen ist. Gibt es ein Cookiejar-Tool für den Umgang mit Cookies in http-Clients? Grundsätzlich möchte ich dem http-Client lib mitteilen: Wenn Sie Set-Cookie-Header erhalten, merken Sie sich diese automatisch und
Cheeso
Dies wäre eine Funktion Ihrer HTTP-Client-Bibliothek Ihrer Wahl. Ich kann Superagent als gutes Beispiel vorschlagen .
Zah
Ich habe es aufgegeben, diese Bibliothek nach ein paar Stunden in Express zum Laufen zu bringen ... benutze stattdessen connect.
Enko
7

So lassen Sie einen Cookie-Splitter mit Cookies arbeiten, deren Cookie-Werte '=' enthalten:

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;
};

dann, um einen individuellen Cookie zu bekommen:

get_cookies(request)['my_cookie']
David Beckwith
quelle
6

Cookies werden über HTTP-Header übertragen.
Sie müssen nur die Anforderungsheader analysieren und Antwortheader einfügen.

Tobias P.
quelle
Wikipedia nicht einfacher
Hos Mercury
2

Hier ist ein ordentlicher Patch zum Kopieren und Einfügen zum Verwalten von Cookies im Knoten. Ich mache das in CoffeeScript, für die Schönheit.

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

Jetzt können Sie Cookies wie erwartet verarbeiten:

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
Philip Orange
quelle
3
Kopieren Sie einfach diesen Code und fügen Sie ihn in die Registerkarte TRY COFFESCRIPT auf coffeescript.org ein . Ihre Antwort hat mir geholfen, und Coffeescript ist nicht so schwer zu lesen, wenn Sie Javascript kennen.
Mattijs
1

Lassen Sie mich diesen Teil der Frage wiederholen, den die Antworten hier ignorieren:

Kann dies in wenigen Codezeilen erfolgen, ohne dass eine Drittanbieter-Bibliothek abgerufen werden muss?


Cookies lesen

Cookies werden aus Anfragen mit dem CookieHeader gelesen . Sie enthalten nur ein nameund value. Aufgrund der Funktionsweise von Pfaden können mehrere gleichnamige Cookies gesendet werden. In NodeJS werden alle Cookies als eine Zeichenfolge angezeigt, wenn sie im CookieHeader gesendet werden . Sie teilen sie mit ;. Sobald Sie einen Cookie haben, ist alles links von den Gleichen (falls vorhanden) das name, und alles danach ist das value. Einige Browser akzeptieren ein Cookie ohne Gleichheitszeichen und nehmen an, dass der Name leer ist. Leerzeichen zählen nicht als Teil des Cookies. Werte können auch in doppelte Anführungszeichen gesetzt werden ( "). Werte können auch enthalten =. Zum Beispiel formula=5+3=8ist ein gültiger 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 Arbeit erleichtert. Dann können Sie gerne object.myCookieNamedarauf zugreifen , um den Wert zu erhalten. Wenn Sie Duplikate erwarten, möchten Sie diese durchlaufen cookieEntries. Browser füttern Cookies mit absteigender Priorität. Durch das Umkehren wird sichergestellt, dass das Cookie mit der höchsten Priorität im Objekt angezeigt wird. (Dies .slice()soll eine Mutation des Arrays vermeiden.)


Einstellungen Cookies

Das "Schreiben" von Cookies erfolgt mithilfe des Set-CookieHeaders in Ihrer Antwort. Das response.headers['Set-Cookie']Objekt ist eigentlich ein Array, also werden Sie darauf drängen. Es akzeptiert eine Zeichenfolge, hat jedoch mehr Werte als nur nameund value. Der schwierigste Teil ist das Schreiben der Zeichenfolge, dies kann jedoch in einer Zeile erfolgen.

/**
 * @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 Set-Cookiein Ihrer Anfrage tatsächlich mehrere Header setzen können. Deshalb ist es ein Array.


Hinweis zu externen Bibliotheken:

Wenn Sie sich entscheiden , die verwenden express, cookie-parseroder cookiestellen sie Standardwerte haben , die nicht Standard sind. Die analysierten Cookies sind immer URI-dekodiert (prozentual dekodiert). Das heißt, wenn Sie einen Namen oder Wert verwenden, der eines der folgenden Zeichen enthält: !#$%&'()*+/:<=>?@[]^`{|}Diese werden in diesen Bibliotheken unterschiedlich behandelt. Wenn Sie Cookies setzen, werden diese mit codiert%{HEX} . Und wenn Sie einen Cookie lesen, müssen Sie ihn entschlüsseln.

Während es sich beispielsweise [email protected]um ein gültiges Cookie handelt, codieren diese Bibliotheken es als email=name%40domain.com. Das Dekodieren kann Probleme verursachen, wenn Sie das %in Ihrem Cookie verwenden. Es wird verstümmelt. Zum Beispiel wird Ihr Cookie, das war: secretagentlevel=50%007and50%006wird secretagentlevel=507and506. Das ist ein Randfall, aber etwas zu beachten, wenn Bibliotheken gewechselt werden.

Außerdem werden in diesen Bibliotheken Cookies mit einer Standardeinstellung festgelegt, path=/was bedeutet, dass sie bei jeder URL-Anforderung an den Host gesendet werden.

Wenn Sie diese Werte selbst zu kodieren oder entschlüsseln möchten, können Sie verwenden , encodeURIComponentoder decodeURIComponent, respectively.


Verweise:


Zusätzliche Information:

ShortFuse
quelle
0

Zuerst muss ein Cookie erstellt werden (ich habe das Token als Beispiel in das Cookie eingewickelt) und dann als Antwort festgelegt werden. Um das Cookie wie folgt zu verwenden, installieren Sie cookieParser

app.use(cookieParser());

Der Browser speichert es auf der Registerkarte "Ressource" und wird für jede Anforderung verwendet, wobei anschließend die ursprüngliche URL als Basis verwendet wird

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

Das Abrufen von Cookies von einer Anforderung auf der Serverseite ist ebenfalls einfach. Sie müssen das Cookie aus der Anforderung extrahieren, indem Sie die Eigenschaft 'cookie' des Anforderungsobjekts aufrufen.

var token = req.cookies.token; // Retrieving Token stored in cookies
Ankit kaushik
quelle
0

Wenn es Ihnen egal ist, was in der Version enthalten ist cookieund Sie sie nur verwenden möchten, versuchen Sie diesen sauberen Ansatz mit request(einem beliebten Knotenmodul):

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
  });
});
BlackBeard
quelle
Entschuldigung, aber dieser Code macht für mich überhaupt keinen Sinn. Ist jar()ein niedlicher Methodenname, um die aktuelle Liste der Cookies zu erhalten? Was ist der Sinn der 2 Aufrufe der Anfrage? Dies ist meistens eine Werbung, keine Antwort.
user1944491
0
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);
}
Simon
quelle
0

Verwenden von ES5 / 6 Sorcery & RegEx Magic

Hier ist eine Option, um die Cookies zu lesen und sie in ein Objekt von Schlüssel zu verwandeln. Wertepaare für die Clientseite könnten es auch serverseitig verwenden.

Hinweis : Wenn =der Wert ein enthält, machen Sie sich keine Sorgen. Wenn es einen =Schlüssel gibt, Ärger im Paradies.

Weitere Hinweise : Einige argumentieren möglicherweise mit der Lesbarkeit, also teilen Sie sie nach Ihren Wünschen auf.

Ich mag Notizen : Das Hinzufügen eines Fehlerbehandlers (try catch) würde nicht schaden.

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}`)
}

Geben Sie hier die Bildbeschreibung ein

Was ist los?

iLikeCookies()teilt die Cookies durch ;( Leerzeichen nach; ):

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

Dann ordnen wir dieses Array zu und teilen es nach dem ersten Auftreten der =Verwendung von Regex-Erfassungsparens auf :

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

Verwenden Sie dann unseren Freund `Object.fromEntries, um dies zu einem Objekt aus Schlüssel- und Wertpaaren zu machen.

Nooice.

Steve
quelle
0

Ich habe diese einfache Funktion nur übergeben req.headers.cookieund Cookie-Namen

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

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