Pobierz i ustaw pojedynczy plik cookie za pomocą serwera HTTP Node.js.

159

Chcę móc ustawić pojedynczy plik cookie i odczytać ten pojedynczy plik cookie przy każdym żądaniu wysyłanym do instancji serwera nodejs. Czy można to zrobić w kilku wierszach kodu, bez konieczności pobierania biblioteki innej firmy?

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

Po prostu próbuję pobrać powyższy kod bezpośrednio z nodejs.org i umieścić w nim plik cookie.

Corey Hart
źródło

Odpowiedzi:

190

Nie ma szybkiego dostępu do funkcji pobierania / ustawiania plików cookie, więc wymyśliłem następujący 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/');

Spowoduje to zapisanie wszystkich plików cookie w obiekcie plików cookie i musisz ustawić pliki cookie podczas pisania nagłówka.

Corey Hart
źródło
11
Powyższy kod będzie działał niepoprawnie, jeśli wartość pliku cookie zawiera =znak równości ( ), jak w jednym z plików cookie Facebooka, takich jak fbm_1234123412341234=base_domain=.domain.com.
Eye
3
czy wartości plików cookie nie muszą być zakodowane w adresie URL / zakodowane procentowo? = w doockie wartość byłaby w tym przypadku nieprawidłowa, prawda?
les2
2
W takim przypadku podzielona do ;tego czasu przez pierwsze wystąpienie =. Lewy to klucz, prawy to wartość.
iLoch
4
Wpadłem na ten sam problem co @Eye, zamiast jechać trasą @iLoch przesiadłem się parts[0]na parts.shift()i parts[1]naparts.join('=')
aron.duby
3
Podany kod zawierał poważne błędy i ludzie próbowali go kopiować. Zobacz moją ostatnią aktualizację
Dan,
124

Jeśli używasz biblioteki Express, tak jak robi to wielu programistów node.js, jest łatwiejszy sposób. Sprawdź stronę dokumentacji Express.js, aby uzyskać więcej informacji.

Powyższy przykład parsowania działa, ale express daje ci fajną funkcję, aby się tym zająć:

app.use(express.cookieParser());

Aby ustawić plik cookie:

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

Aby wyczyścić plik cookie:

res.clearCookie('cookiename');
RevNoah
źródło
14
Biblioteka plików cookie pochodzi w rzeczywistości z połączenia biblioteki podstawowej; nie musisz brać wszystkich ekspresowych, aby uzyskać pomocnika plików cookie.
Ajax
1
w rzeczywistości biblioteka plików cookie nie jest częścią connect (która nie może ustawić plików cookie)
framp
10
cookie-parsernie jest już częścią Express i / lub Connect, ale jest dostępny jako oprogramowanie pośredniczące: github.com/expressjs/cookie-parser
Koen.
7
Jak w tym przykładzie „zdobyć” plik cookie? Za kompletność i odpowiedź na pytanie.
hubatish
1
Głosowanie w dół z powodu konieczności zainstalowania Express tylko po to, aby używać plików cookie
Steven
34

RevNoah miał najlepszą odpowiedź, sugerując użycie parsera plików cookie Express . Ale ta odpowiedź ma teraz 3 lata i jest nieaktualna.

Korzystając z Express , możesz odczytać plik cookie w następujący sposób

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

I zaktualizuj swoją package.jsonnastępującą, zastępując odpowiednie względnie najnowsze wersje.

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

Więcej operacji, takich jak ustawianie i analizowanie plików cookie, opisano tutaj i tutaj

Kirby
źródło
8
Pytanie dotyczy tego, jak zdobyć i ustawić. Aby ustawić użyj tego:res.cookie('cookieName', cookieValue, { maxAge: 900000, httpOnly: true });
Augie Gardner
Czy możesz ustawić i pobierać pliki cookie w ramach jednej sesji (bez konieczności znajomości i obsługi kluczy)?
Matej J,
12

Jako rozszerzenie odpowiedzi @Corey Hart, przepisałem parseCookies()użycie:

  • RegExp.prototype.exec - użyj wyrażenia regularnego, aby przeanalizować ciągi „nazwa = wartość”

Oto działający przykład:

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

Zwracam również uwagę, że OP korzysta z modułu http. Jeśli OP używał restify , może skorzystać 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);
Stephen Quan
źródło
1
kilka sugestii teraz, 3,5 roku później, dla przyszłych widzów. Użyj let/consti stringifyCookiesmoże być wypełniony a mapzamiast budować tablicę w ten sposób.
Ascherer
10

Możesz skorzystać z modułu „cookies” npm, który posiada rozbudowany zestaw funkcji.

Dokumentacja i przykłady na:
https://github.com/jed/cookies

zah
źródło
1
Wygląda na to, że ten moduł jest przeznaczony do użytku na serwerach http. Czy istnieje narzędzie Cookiejar do obsługi plików cookie w klientach http? Zasadniczo nie mogę powiedzieć klientowi http: lib: jeśli otrzymasz jakiekolwiek nagłówki Set-Cookie, zapamiętaj je automatycznie, a następnie przekaż w razie potrzeby kolejne żądania wychodzące (gdy domena się zgadza).
Cheeso
Byłaby to funkcja wybranej przez Ciebie biblioteki klienta HTTP. Mogę zasugerować superagenta jako dobry przykład.
zah
Zrezygnowałem z prób, aby ta biblioteka działała ekspresowo po kilku godzinach ... zamiast tego użyj connect.
enko
7

Aby ustawić rozdzielacz plików cookie do pracy z plikami cookie, które mają w wartościach 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;
};

następnie, aby uzyskać indywidualny plik cookie:

get_cookies(request)['my_cookie']
David Beckwith
źródło
6

Pliki cookie są przesyłane przez nagłówki HTTP.
Będziesz musiał tylko przeanalizować nagłówki żądań i umieścić nagłówki odpowiedzi.

Tobias P.
źródło
Wikipedia nie jest łatwiejsza
Hos Mercury
2

Oto zgrabna łatka kopiuj-wklej do zarządzania plikami cookie w węźle. Zrobię to w CoffeeScript, dla piękna.

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

Teraz możesz obsługiwać pliki cookie zgodnie z oczekiwaniami:

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
źródło
3
Po prostu skopiuj i wklej ten kod w zakładce WYPRÓBUJ KAWĘ na coffeescript.org . Twoja odpowiedź pomogła mi, a coffeescript nie jest trudny do odczytania, jeśli znasz javascript.
Mattijs,
1

Powtórzę tę część pytania, na które odpowiedzi tutaj ignorują:

Czy można to zrobić w kilku wierszach kodu, bez konieczności pobierania biblioteki innej firmy?


Czytanie plików cookie

Pliki cookie są odczytywane z żądań z Cookienagłówkiem. Zawierają tylko namei value. Ze względu na sposób działania ścieżek można wysłać wiele plików cookie o tej samej nazwie. W NodeJS wszystkie pliki cookie w postaci jednego ciągu, gdy są wysyłane w Cookienagłówku. Dzielisz ich z ;. Gdy masz plik cookie, wszystko po lewej stronie równa się (jeśli występuje) to name, a wszystko po nim to value. Niektóre przeglądarki akceptują plik cookie bez znaku równości i zakładają, że nazwa jest pusta. Spacje nie są liczone jako część pliku cookie. Wartości można również zawijać w podwójne cudzysłowy ( "). Wartości mogą również zawierać =. Na przykład formula=5+3=8jest prawidłowym plikiem 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());

Jeśli nie spodziewasz się zduplikowanych nazw, możesz przekonwertować je na obiekt, co ułatwi sprawę. Następnie możesz uzyskać dostęp, object.myCookieNameaby uzyskać wartość. Jeśli spodziewasz się duplikatów, chcesz powtórzyć cookieEntries. Przeglądarki podają pliki cookie w malejącym priorytecie, więc cofanie zapewnia, że ​​w obiekcie pojawia się plik cookie o najwyższym priorytecie. (Ma .slice()to na celu uniknięcie mutacji tablicy).


Ustawienia plików cookie

„Zapisywanie” plików cookie odbywa się za pomocą Set-Cookienagłówka w Twojej odpowiedzi. response.headers['Set-Cookie']Obiekt jest rzeczywiście tablicą, więc będziesz popychanie do niego. Akceptuje ciąg, ale ma więcej wartości niż tylko namei value. Najtrudniejszą częścią jest napisanie ciągu, ale można to zrobić w jednej linii.

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

Pamiętaj, że możesz ustawić wiele plików cookie, ponieważ w rzeczywistości możesz ustawić wiele Set-Cookienagłówków w swoim żądaniu. Dlatego jest to tablica.


Uwaga dotycząca bibliotek zewnętrznych:

Jeśli użytkownik zdecyduje się użyć express, cookie-parseralbo cookie, trzeba pamiętać, że mają wartości domyślne, które są niestandardowe. Analizowane pliki cookie są zawsze dekodowane w postaci URI (dekodowane procentowo). Oznacza to, że jeśli użyjesz nazwy lub wartości, która zawiera którykolwiek z następujących znaków: !#$%&'()*+/:<=>?@[]^`{|}będą one obsługiwane inaczej w tych bibliotekach. Jeśli ustawiasz pliki cookie, są one kodowane za pomocą%{HEX} . A jeśli czytasz plik cookie, musisz je zdekodować.

Na przykład, chociaż [email protected]jest to prawidłowy plik cookie, te biblioteki zakodują go jako plik email=name%40domain.com. Dekodowanie może powodować problemy, jeśli używasz %pliku cookie. Zostanie zmiażdżony. Na przykład Twój plik cookie, który był: secretagentlevel=50%007and50%006staje się secretagentlevel=507and506. To skrajny przypadek, ale coś, na co należy zwrócić uwagę, jeśli zmieniasz biblioteki.

Ponadto w tych bibliotekach pliki cookie mają ustawienie domyślne, path=/co oznacza, że ​​są wysyłane przy każdym żądaniu adresu URL do hosta.

Jeśli chcesz samodzielnie zakodować lub zdekodować te wartości, możesz użyć odpowiednio encodeURIComponentlub decodeURIComponent.


Bibliografia:


Dodatkowe informacje:

ShortFuse
źródło
0

Najpierw należy utworzyć ciasteczko (jako przykład zawiniłem token wewnątrz ciasteczka), a następnie ustawić w odpowiedzi. Aby użyć ciasteczka w następujący sposób zainstaluj cookieParser

app.use(cookieParser());

Przeglądarka zapisze go na karcie „Zasoby” i będzie używany do każdego żądania, przyjmując początkowy adres URL jako podstawę

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

Uzyskanie pliku cookie z żądania po stronie serwera jest również łatwe. Musisz wyodrębnić plik cookie z żądania, wywołując właściwość „cookie” obiektu żądania.

var token = req.cookies.token; // Retrieving Token stored in cookies
Ankit kaushik
źródło
0

Jeśli nie obchodzi cię, co jest w środku cookiei po prostu chcesz z tego skorzystać, wypróbuj to czyste podejście za pomocą request(popularnego modułu węzłowego):

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
  });
});
Czarnobrody
źródło
Przepraszam, ale ten kod nie ma dla mnie żadnego sensu. Czy jest jar()jakaś urocza nazwa metody, aby uzyskać aktualną listę plików cookie? Jaki jest sens dwóch wezwań prośby? To głównie reklama, a nie odpowiedź.
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);
}
Szymon
źródło
0

Korzystanie z niektórych ES5 / 6 Sorcery & RegEx Magic

Tutaj jest opcja, aby odczytać pliki cookie i przekształcić je w obiekt pary klucz, wartość po stronie klienta, można go również użyć po stronie serwera.

Uwaga : jeśli =w wartości jest a , nie martw się. Jeśli jest =w kluczu, kłopoty w raju.

Więcej uwag : Niektórzy mogą twierdzić, że czytelność jest czytelna, więc podziel ją według własnego uznania.

Lubię notatki : Dodanie modułu obsługi błędów (spróbuj złapać) nie zaszkodzi.

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

wprowadź opis obrazu tutaj

Co się dzieje?

iLikeCookies()podzieli pliki cookie według ;( spacja po; ):

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

Następnie mapujemy tę tablicę i dzielimy na pierwsze wystąpienie =użycia par do przechwytywania wyrażeń regularnych :

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

Następnie użyj naszego przyjaciela `Object.fromEntries, aby uczynić ten obiekt parami klucz, wartości.

Nooice.

Steve
źródło
0

Napisałem tę prostą funkcję po prostu podaj req.headers.cookiei nazwę pliku 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
}
Ahmed Magdy
źródło