Obter e definir um único cookie com o servidor HTTP Node.js.


159

Quero poder definir um único cookie e ler esse cookie único com cada solicitação feita à instância do servidor nodejs. Isso pode ser feito em algumas linhas de código, sem a necessidade de puxar uma lib de terceiros?

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

Apenas tentando pegar o código acima diretamente do nodejs.org e inserir um cookie nele.

Respostas:


190

Não há acesso rápido às funções para obter / configurar cookies, então criei o seguinte hack:

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

Isso armazenará todos os cookies no objeto de cookies e você precisará configurá-los quando escrever a cabeça.


11
O código acima funcionará incorretamente se o valor de um cookie contiver um =sinal de igual ( ) como em um dos cookies do Facebook, como fbm_1234123412341234=base_domain=.domain.com.
— Olho

3
os valores dos cookies não precisam ser codificados em URL / codificado em porcentagem? = no valor doockie seria inválido nesse caso, certo?
— les2

2
Nesse caso, divida até ;então pela primeira instância de =. Esquerda é a chave, direita é valor.
— ILoch

4
Corri para o mesmo problema que @Eye, em vez de ir a rota de @iLoch eu mudei parts[0]para parts.shift()e parts[1]paraparts.join('=')
— aron.duby

3
O código fornecido apresentava bugs graves e as pessoas costumavam copiá-lo. Veja minha última atualização
— Dan

124

Se você estiver usando a biblioteca expressa, como fazem muitos desenvolvedores do node.js., existe uma maneira mais fácil. Consulte a página de documentação do Express.js para obter mais informações.

O exemplo de análise acima funciona, mas express fornece uma boa função para cuidar disso:

app.use(express.cookieParser());

Para definir um cookie:

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

Para limpar o cookie:

res.clearCookie('cookiename');

14
A biblioteca de cookies é realmente da conexão da biblioteca subjacente; você não precisa usar todo o expresso para obter ajuda de cookies.
— Ajax

1
na verdade, a biblioteca cookie não é parte de conexão (que não é possível definir cookie)
— framp

10
cookie-parsernão faz mais parte do express e / ou da conexão, mas está disponível como middleware: github.com/expressjs/cookie-parser
— Koen.

7
Como alguém "obtém" um cookie neste exemplo? Para completar e responder à pergunta.
— Julio

1
Downvoting devido à necessidade de instalar expressar apenas para usam cookies
— Steven

34

RevNoah teve a melhor resposta com a sugestão de usar o analisador de cookies do Express . Mas, essa resposta agora tem 3 anos e está desatualizada.

Usando o Express , você pode ler um cookie da seguinte maneira

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 atualize o seu package.jsoncom o seguinte, substituindo as versões relativamente mais recentes apropriadas.

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

Mais operações, como configurar e analisar cookies, são descritas aqui e aqui


8
A pergunta pergunta como obter e definir. Para definir, use isto: #res.cookie('cookieName', cookieValue, { maxAge: 900000, httpOnly: true });
— Augie Gardner

Você pode definir e obter cookies por sessão (sem a necessidade de conhecer e manipular chaves)?
— precisa

12

Como aprimoramento da resposta de @Corey Hart, reescrevi o parseCookies()uso:

Aqui está o exemplo de trabalho:

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

Percebo também que o OP usa o módulo http. Se o OP estava usando restify , ele pode fazer uso de 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);

1
algumas sugestões agora, 3,5 anos depois, para futuros espectadores. Use let/conste stringifyCookiespode ser alinhado com um em mapvez de construir uma matriz dessa maneira.
— Ascherer

10

Você pode usar o módulo npm "cookies", que possui um conjunto abrangente de recursos.

Documentação e exemplos em:
https://github.com/jed/cookies


1
Parece que esse módulo deve ser usado em servidores http. Existe uma ferramenta cookiejar para manipular cookies em clientes http? Basicamente, devo informar à lib do cliente http: se você obtiver algum cabeçalho Set-Cookie, lembre-se automaticamente e depois repasse as solicitações de saída subsequentes conforme apropriado (quando o domínio corresponder).
— Cheeso

Esse seria um recurso da sua biblioteca cliente http de escolha. Eu posso sugerir superagente como um bom exemplo.
— ZAH

Desisti de tentar fazer com que essa biblioteca funcionasse expressamente após algumas horas ... use o connect.
— enko 27/08/13

7

Para que um divisor de cookies funcione com cookies que tenham '=' nos valores dos cookies:

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

para obter um cookie individual:

get_cookies(request)['my_cookie']


2

Aqui está um patch puro de copiar e colar para gerenciar cookies no nó. Farei isso no CoffeeScript, pela beleza.

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

Agora você poderá manipular cookies da maneira esperada:

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
Basta copiar e colar esse código na guia TRY COFFESCRIPT no coffeescript.org . Sua resposta me ajudou e o coffeescript não é tão difícil de ler se você souber javascript.
— Mattijs

1

Deixe-me repetir esta parte da pergunta que as respostas aqui estão ignorando:

Isso pode ser feito em algumas linhas de código, sem a necessidade de puxar uma lib de terceiros?


Lendo Cookies

Os cookies são lidos a partir de solicitações com o Cookiecabeçalho. Eles incluem apenas um namee value. Devido à maneira como os caminhos funcionam, vários cookies com o mesmo nome podem ser enviados. No NodeJS, todos os cookies são inseridos como uma sequência, pois são enviados no Cookiecabeçalho. Você os separou ;. Depois de ter um cookie, tudo à esquerda dos iguais (se houver) é o name, e tudo depois é o value. Alguns navegadores aceitam um cookie sem sinal de igual e assumem o nome em branco. Espaços em branco não contam como parte do cookie. Os valores também podem ser colocados entre aspas duplas ( "). Os valores também podem conter =. Por exemplo, formula=5+3=8é um cookie válido.

/**
 * @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 você não está esperando nomes duplicados, pode converter em um objeto que facilita as coisas. Então você pode acessar como object.myCookieNamepara obter o valor. Se você está esperando duplicatas, deseja fazer a iteração cookieEntries. Os navegadores alimentam os cookies com prioridade decrescente, portanto, a reversão garante que o cookie de maior prioridade seja exibido no objeto. (O .slice()objetivo é evitar a mutação da matriz.)


Cookies de configurações

"Escrever" cookies é feito usando o Set-Cookiecabeçalho na sua resposta. O response.headers['Set-Cookie']objeto é realmente uma matriz, então você estará pressionando para isso. Ele aceita uma string, mas tem mais valores do que apenas namee value. A parte mais difícil é escrever a string, mas isso pode ser feito em uma linha.

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

Lembre-se de que você pode definir vários cookies, porque na verdade pode definir vários Set-Cookiecabeçalhos em sua solicitação. É por isso que é uma matriz.


Nota sobre bibliotecas externas:

Se você decidir usar o express,, cookie-parserou cookie, observe que eles têm padrões que não são padrão. Os cookies analisados ​​são sempre decodificados por URI (decodificado em porcentagem). Isso significa que, se você usar um nome ou valor com qualquer um dos seguintes caracteres: !#$%&'()*+/:<=>?@[]^`{|}eles serão tratados de maneira diferente com essas bibliotecas. Se você estiver configurando cookies, eles serão codificados %{HEX}. E se você estiver lendo um cookie, precisará decodificá-lo.

Por exemplo, embora email=name@domain.comseja um cookie válido, essas bibliotecas o codificarão como email=name%40domain.com. A decodificação pode apresentar problemas se você estiver usando o %em seu cookie. Vai ficar mutilado. Por exemplo, seu cookie que era: secretagentlevel=50%007and50%006se torna secretagentlevel=507and506. Esse é um caso extremo, mas algo a ser observado se você mudar de biblioteca.

Além disso, nessas bibliotecas, os cookies são configurados com um padrão, o path=/que significa que eles são enviados a cada solicitação de URL para o host.

Se você desejar codificar ou decodificar esses valores, poderá usar encodeURIComponentou decodeURIComponent, respectivamente.


Referências:


Informação adicional:


0

Primeiro, é necessário criar um cookie (envolvi o token dentro do cookie como exemplo) e depois defini-lo em resposta.Para usar o cookie da seguinte maneira, instale o cookieParser

app.use(cookieParser());

O navegador o salvará na guia 'Recurso' e será usado para todas as solicitações posteriores, tendo o URL inicial como base

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

Também é fácil obter o cookie de uma solicitação no lado do servidor. Você precisa extrair o cookie da solicitação chamando a propriedade 'cookie' do objeto de solicitação.

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

0

Se você não se importa com o conteúdo cookiee deseja apenas usá-lo, tente esta abordagem limpa usando request(um módulo de nó popular):

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

Desculpe, mas esse código não faz nenhum sentido para mim. Algum jar()nome de método atraente para obter a lista atual de cookies? Qual é o sentido das 2 invocações de solicitação? Isso é principalmente um anúncio, não uma resposta.
— 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 alguma feitiçaria ES5 / 6 e magia RegEx

Aqui está uma opção para ler os cookies e transformá-los em um objeto Chave, pares de valor para o lado do cliente, também pode usá-lo no lado do servidor.

Nota : Se houver um =valor, não se preocupe. Se houver um =na chave, problemas no paraíso.

Mais notas : alguns podem argumentar legibilidade, então divida-o como quiser.

Gosto de notas : adicionar um manipulador de erros (try catch) não faria mal.

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

insira a descrição da imagem aqui

O que está acontecendo?

iLikeCookies()irá dividir os cookies por ;( espaço depois; ):

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

Em seguida, mapeamos essa matriz e dividimos pela primeira ocorrência do =uso de captura de expressões regulares :

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

Em seguida, use nosso amigo `Object.fromEntries para tornar isso um objeto de pares de chaves, val.

Nooice.


0

Eu escrevi essa função simples, basta passar req.headers.cookiee nome do 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
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.