Ottieni e imposta un singolo cookie con il server HTTP Node.js


159

Voglio poter impostare un singolo cookie e leggere quel singolo cookie con ogni richiesta fatta all'istanza del server nodejs. Può essere fatto in poche righe di codice, senza la necessità di inserire una lib di terze parti?

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

Sto solo cercando di prendere il codice sopra direttamente da nodejs.org e di inserire un cookie in esso.

Risposte:


190

Non esiste un accesso rapido alle funzioni per ottenere / impostare i cookie, quindi ho trovato il seguente trucco:

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

Ciò memorizzerà tutti i cookie nell'oggetto cookie e devi impostare i cookie quando scrivi la testa.


11
Il codice sopra funzionerà in modo errato se il valore di un cookie contiene un =segno uguale ( ) come in uno dei cookie di Facebook come fbm_1234123412341234=base_domain=.domain.com.
Occhio

3
i valori dei cookie non devono essere codificati in URL / codificati in percentuale? = nel valore di Doockie non sarebbe valido in quel caso, giusto?
les2

2
In tal caso diviso per ;allora dalla prima istanza di =. Sinistra è la chiave, destra è il valore.
iLoch,

4
Ho incontrato lo stesso problema come @Eye, invece di andare il percorso di @iLoch sono passato parts[0]a parts.shift()ed parts[1]aparts.join('=')
aron.duby

3
Il codice fornito aveva gravi bug e la gente cercava di copiarlo. Vedi il mio ultimo aggiornamento
Dan,

124

Se stai usando la libreria express, come fanno molti sviluppatori node.js, c'è un modo più semplice. Controllare la pagina della documentazione Express.js per ulteriori informazioni.

L'esempio di analisi sopra funziona ma express ti dà una bella funzione per occupartene:

app.use(express.cookieParser());

Per impostare un cookie:

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

Per cancellare il cookie:

res.clearCookie('cookiename');

14
La libreria dei cookie proviene effettivamente dalla libreria sottostante connessa; non è necessario prendere tutto express per ottenere cookie helper.
Ajax

1
in realtà la libreria dei cookie non fa parte di connect (che non può impostare i cookie)
da

10
cookie-parsernon fa più parte di express e / o connect, ma è disponibile come middleware: github.com/expressjs/cookie-parser
Koen.

7
Come si fa a "ottenere" un cookie in questo esempio? Per completezza e risposta alla domanda.
arrogante

1
Downvoting a causa della necessità di installare express solo per utilizzare i cookie
Steven

34

RevNoah ha avuto la risposta migliore con il suggerimento di utilizzare il parser di cookie di Express . Ma quella risposta ora ha 3 anni ed è obsoleta.

Usando Express , puoi leggere un cookie come segue

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']);
})

E aggiorna il tuo package.jsoncon il seguente, sostituendo le versioni relativamente recenti appropriate.

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

Altre operazioni come l'impostazione e l'analisi dei cookie sono descritte qui e qui


8
La domanda chiede come ottenere e impostare. Per impostare usa questo:res.cookie('cookieName', cookieValue, { maxAge: 900000, httpOnly: true });
Augie Gardner il

Puoi impostare e ottenere i cookie come una sessione (senza la necessità di conoscere e gestire le chiavi)?
Matej J,

12

Per migliorare la risposta di @Corey Hart, ho riscritto l' parseCookies()utilizzo di:

Ecco l'esempio funzionante:

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

Noto anche che l'OP utilizza il modulo http. Se l'OP utilizzava Restify , può utilizzare i cookie di restify :

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

1
alcuni suggerimenti ora, 3,5 anni dopo, per i futuri spettatori. Usa let/conste stringifyCookiespuò essere allineato con un mapinvece di costruire un array in quel modo.
Ascherer,

10

È possibile utilizzare il modulo npm "cookies", che presenta un set completo di funzionalità.

Documentazione ed esempi su:
https://github.com/jed/cookies


1
Sembra che quel modulo sia destinato all'uso nei server http. Esiste uno strumento cookiejar per la gestione dei cookie nei client http? Fondamentalmente non posso dire alla libreria client http: se ottieni intestazioni Set-Cookie, ricordale automaticamente e quindi passa le successive richieste in uscita come appropriato (quando il dominio corrisponde).
Cheeso,

Questa sarebbe una caratteristica della tua libreria client HTTP preferita. Posso suggerire il superagente come un buon esempio.
zah,

Smettila di provare a far funzionare questa libreria in express dopo un paio d'ore ... usa invece connect.
enko,

7

Per far funzionare uno splitter cookie con cookie che hanno '=' nei valori dei 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;
};

quindi per ottenere un singolo cookie:

get_cookies(request)['my_cookie']


2

Ecco una bella copia-incolla per gestire i cookie nel nodo. Lo farò in CoffeeScript, per la bellezza.

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

Ora sarai in grado di gestire i cookie come ti aspetteresti:

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

3
Copia semplicemente quel codice nella scheda TRY COFFESCRIPT su coffeescript.org . La tua risposta mi ha aiutato e coffeescript non è così difficile da leggere se conosci javascript.
Mattijs,

1

Vorrei ripetere questa parte della domanda che le risposte qui stanno ignorando:

Può essere fatto in poche righe di codice, senza la necessità di inserire una lib di terze parti?


Lettura dei cookie

I cookie vengono letti dalle richieste con l' Cookieintestazione. Includono solo un namee value. A causa del modo in cui funzionano i percorsi, è possibile inviare più cookie con lo stesso nome. In NodeJS, tutti i cookie vengono inseriti in un'unica stringa quando vengono inviati Cookienell'intestazione. Li hai divisi con ;. Una volta che hai un cookie, tutto a sinistra degli uguali (se presente) è il name, e tutto ciò che segue è il value. Alcuni browser accetteranno un cookie senza segno di uguale e presumeranno il nome vuoto. Gli spazi bianchi non contano come parte del cookie. I valori possono anche essere racchiusi tra virgolette doppie ( "). I valori possono anche contenere =. Ad esempio, formula=5+3=8è un cookie valido.

/**
 * @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());

Se non ti aspetti nomi duplicati, puoi convertirlo in un oggetto che semplifica le cose. Quindi è possibile accedere come object.myCookieNameper ottenere il valore. Se ti aspetti duplicati, allora vuoi farlo scorrere cookieEntries. I browser alimentano i cookie con priorità decrescente, pertanto l'inversione garantisce che nell'oggetto venga visualizzato il cookie con priorità più alta. (Il .slice()per evitare la mutazione dell'array.)


Impostazioni cookie

La "scrittura" dei cookie viene eseguita utilizzando l' Set-Cookieintestazione nella risposta. L' response.headers['Set-Cookie']oggetto è in realtà un array, quindi ti spingerai ad esso. Accetta una stringa ma ha più valori di solo namee value. La parte più difficile è scrivere la stringa, ma questo può essere fatto in una riga.

/**
 * @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);

Ricorda che puoi impostare più cookie perché puoi effettivamente impostare più Set-Cookieintestazioni nella tua richiesta. Ecco perché è un array.


Nota sulle librerie esterne:

Se si decide di utilizzare la express,, cookie-parsero cookie, notare che hanno valori predefiniti non standard. I cookie analizzati sono sempre decodificati URI (decodificati in percentuale). Ciò significa che se si utilizza un nome o un valore con uno dei seguenti caratteri: !#$%&'()*+/:<=>?@[]^`{|}verranno gestiti in modo diverso con tali librerie. Se stai impostando i cookie, vengono codificati %{HEX}. E se stai leggendo un cookie devi decodificarli.

Ad esempio, mentre email=name@domain.comè un cookie valido, queste librerie lo codificheranno come email=name%40domain.com. La decodifica può presentare problemi se si utilizza il %cookie. Verrà rovinato. Ad esempio, il tuo cookie che era: secretagentlevel=50%007and50%006diventasecretagentlevel=507and506 . Questo è un caso limite, ma qualcosa da notare se si cambia libreria.

Inoltre, su queste librerie, i cookie sono impostati con un valore predefinito, il path=/che significa che vengono inviati su ogni richiesta url all'host.

Se vuoi codificare o decodificare questi valori tu stesso, puoi usare encodeURIComponento decodeURIComponent, rispettivamente.


Riferimenti:


Informazioni aggiuntive:


0

Per prima cosa è necessario creare un cookie (ho incluso il token all'interno del cookie come esempio) e quindi impostarlo in risposta. Per utilizzare il cookie nel modo seguente installare cookieParser

app.use(cookieParser());

Il browser lo salverà nella sua scheda "Risorsa" e verrà utilizzato per ogni richiesta successiva prendendo l'URL iniziale come base

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

Anche ottenere cookie da una richiesta sul lato server è semplice. Devi estrarre il cookie dalla richiesta chiamando la proprietà 'cookie' dell'oggetto richiesta.

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

0

Se non ti interessa cosa c'è nel cookiee vuoi solo usarlo, prova questo approccio pulito usando request(un modulo nodo popolare):

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

Ci dispiace, ma questo codice non ha alcun senso per me. È jar()un nome metodo cutesy per ottenere l'elenco corrente dei cookie? Qual è il punto delle 2 invocazioni della richiesta? Questa è principalmente una pubblicità, non una risposta.
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);
}

0

Usando un po 'di stregoneria ES5 / 6 e Magia di RegEx

Ecco un'opzione per leggere i cookie e trasformarli in un oggetto Key, coppie di valori per lato client, che potrebbero anche usarlo lato server.

Nota : se è presente un =valore, nessuna preoccupazione. Se c'è una =chiave, guai in paradiso.

Altre note : alcuni potrebbero sostenere la leggibilità, quindi suddividila come preferisci.

Mi piacciono le note : l'aggiunta di un gestore degli errori (provare a catturare) non farebbe male.

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

inserisci qui la descrizione dell'immagine

Cosa sta succedendo?

iLikeCookies()dividerà i cookie per ;( spazio dopo; ):

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

Quindi mappiamo quell'array e suddividiamo per la prima occorrenza =dell'utilizzo di regex catturando parentesi :

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

Quindi usa il nostro amico `Object.fromEntries per rendere questo un oggetto chiave, coppie di val.

Nooice.


0

Ho scritto questa semplice funzione, basta passare req.headers.cookiee il nome del 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
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.