Dapatkan dan Tetapkan Cookie Tunggal dengan Node.js HTTP Server


159

Saya ingin dapat menetapkan satu cookie, dan membaca cookie tunggal itu dengan setiap permintaan yang dibuat ke instance server nodejs. Bisakah itu dilakukan dalam beberapa baris kode, tanpa perlu menarik lib pihak ketiga?

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

Hanya mencoba mengambil kode di atas secara langsung dari nodejs.org, dan menjalankan cookie ke dalamnya.

Jawaban:


190

Tidak ada akses fungsi cepat untuk mendapatkan / mengatur cookie, jadi saya membuat hack berikut:

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

Ini akan menyimpan semua cookie ke objek cookie, dan Anda perlu mengatur cookie saat Anda menulis kepala.


11
Kode di atas akan berfungsi secara salah jika nilai cookie berisi tanda sama dengan ( =) seperti di salah satu cookie Facebook seperti fbm_1234123412341234=base_domain=.domain.com.
Eye

3
tidakkah nilai cookie harus di-encode URL / persen di-encode? = dalam nilai doockie tidak valid dalam kasus itu, kan?
les2

2
Dalam hal itu dibagi ;saat itu dengan contoh pertama dari =. Kiri adalah kunci, kanan adalah nilai.
iLoch

4
Saya mengalami masalah yang sama dengan @Eye, alih-alih menempuh rute @iLoch saya beralih parts[0]ke parts.shift()dan parts[1]keparts.join('=')
aron.duby

3
Kode yang diberikan memiliki bug serius dan orang-orang terpaksa menyalinnya. Lihat pembaruan terakhir saya
Dan

124

Jika Anda menggunakan pustaka cepat, seperti yang dilakukan banyak pengembang node.js, ada cara yang lebih mudah. Periksa halaman dokumentasi Express.js untuk informasi lebih lanjut.

Contoh parsing di atas berfungsi tetapi express memberi Anda fungsi yang bagus untuk mengatasinya:

app.use(express.cookieParser());

Untuk mengatur cookie:

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

Untuk menghapus cookie:

res.clearCookie('cookiename');

14
Pustaka cookie sebenarnya dari koneksi pustaka yang mendasarinya; Anda tidak perlu mengambil semua express untuk mendapatkan cookie helper.
Ajax

1
sebenarnya perpustakaan cookie bukan bagian dari connect (yang tidak dapat mengatur cookie)
framp

10
cookie-parsertidak lagi menjadi bagian dari express dan / atau connect, tetapi tersedia sebagai middleware: github.com/expressjs/cookie-parser
Koen.

7
Bagaimana seseorang "mendapatkan" cookie dalam contoh ini? Untuk kelengkapan dan menjawab pertanyaan.
hubatish

1
Mengundurkan diri karena harus menginstal express hanya untuk menggunakan cookie
Steven

34

RevNoah memiliki jawaban terbaik dengan saran menggunakan pengurai cookie Express . Tapi, jawaban itu sekarang sudah 3 tahun dan ketinggalan zaman.

Menggunakan Express , Anda dapat membaca cookie sebagai berikut

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

Dan perbarui package.jsondengan yang berikut, gantikan versi yang relatif terbaru yang sesuai.

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

Lebih banyak operasi seperti pengaturan dan penguraian cookie dijelaskan di sini dan di sini


8
Pertanyaannya adalah bagaimana cara mendapatkan dan mengatur. Untuk mengatur menggunakan ini:res.cookie('cookieName', cookieValue, { maxAge: 900000, httpOnly: true });
Augie Gardner

Bisakah Anda menetapkan dan mendapatkan cookie sebagai per sesi (tanpa perlu mengetahui dan menangani kunci)?
Matej J

12

Sebagai tambahan untuk jawaban @Corey Hart, saya telah menulis ulang parseCookies()menggunakan:

Ini contoh kerjanya:

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

Saya juga mencatat bahwa OP menggunakan modul http. Jika OP menggunakan restify , ia dapat menggunakan cookies 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
beberapa saran sekarang, 3,5 tahun kemudian, untuk pemirsa di masa depan. Gunakan let/constdan stringifyCookiesbisa menjadi satu baris dengan mapbukannya membangun array dengan cara itu.
Ascherer

10

Anda dapat menggunakan modul "cookies" npm, yang memiliki serangkaian fitur lengkap.

Dokumentasi dan contoh di:
https://github.com/jed/cookies


1
Sepertinya modul itu dimaksudkan untuk digunakan di server http. Apakah ada alat cookiejar untuk menangani cookie di klien http? Pada dasarnya saya tidak ingin memberitahu http klien lib: jika Anda mendapatkan header Set-Cookie, ingat mereka secara otomatis, dan kemudian meneruskan permintaan keluar berikutnya sesuai yang sesuai (ketika domain cocok).
Cheeso

Ini akan menjadi fitur perpustakaan klien http pilihan Anda. Saya dapat menyarankan superagent sebagai contoh yang baik.
zah

Berhenti mencoba untuk membuat lib ini bekerja di express setelah beberapa jam ... gunakan koneksi saja.
enko

7

Untuk mendapatkan pembagi cookie agar berfungsi dengan cookie yang memiliki '=' dalam nilai 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;
};

lalu untuk mendapatkan satu cookie:

get_cookies(request)['my_cookie']


2

Ini tambalan copy-n-paste yang rapi untuk mengelola cookie di node Saya akan melakukan ini dalam CoffeeScript, untuk kecantikan.

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

Sekarang Anda dapat menangani cookie seperti yang Anda harapkan:

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
Cukup salin tempel kode itu di tab COFFESCRIPT TRY di coffeescript.org . Jawaban Anda memang membantu saya, dan naskah kopi tidak terlalu sulit dibaca jika Anda tahu javascript.
Mattijs

1

Izinkan saya mengulangi bagian pertanyaan ini yang diabaikan oleh jawaban di sini:

Bisakah itu dilakukan dalam beberapa baris kode, tanpa perlu menarik lib pihak ketiga?


Membaca Cookie

Cookie dibaca dari permintaan dengan Cookietajuk. Mereka hanya menyertakan a namedan value. Karena cara kerja jalur, beberapa cookie dengan nama yang sama dapat dikirim. Di NodeJS, semua Cookies dalam satu string saat dikirim di Cookieheader. Anda membaginya dengan ;. Setelah Anda memiliki cookie, semua yang ada di sebelah kiri sama dengan (jika ada) adalah name, dan semuanya adalah value. Beberapa browser akan menerima cookie tanpa tanda yang sama dan menganggap namanya kosong. Spasi putih tidak dihitung sebagai bagian dari cookie. Nilai juga dapat dibungkus dengan tanda kutip ganda ( "). Nilai juga bisa mengandung =. Misalnya, formula=5+3=8adalah cookie yang valid.

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

Jika Anda tidak mengharapkan nama yang digandakan, maka Anda dapat mengonversi ke objek yang mempermudah. Maka Anda dapat mengakses suka object.myCookieNameuntuk mendapatkan nilai. Jika Anda mengharapkan duplikat, maka Anda ingin mengulanginya cookieEntries. Browser memberi makan cookie dalam prioritas menurun, jadi membalikkan memastikan cookie prioritas tertinggi muncul di objek. ( .slice()Adalah untuk menghindari mutasi array.)


Pengaturan Cookie

Cookie "Menulis" dilakukan dengan menggunakan Set-Cookietajuk di respons Anda. The response.headers['Set-Cookie']objek sebenarnya sebuah array, sehingga Anda akan mendorong untuk itu. Ini menerima string tetapi memiliki nilai lebih dari sekadar namedan value. Bagian tersulit adalah menulis string, tetapi ini bisa dilakukan dalam satu baris.

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

Ingat Anda dapat mengatur beberapa cookie, karena Anda sebenarnya dapat mengatur beberapa Set-Cookieheader dalam permintaan Anda. Itu sebabnya array.


Catatan tentang perpustakaan eksternal:

Jika Anda memutuskan untuk menggunakan express, cookie-parseratau cookie, perhatikan mereka memiliki default yang non-standar. Cookies yang diurai selalu URI Decoded (persen-decode). Itu berarti jika Anda menggunakan nama atau nilai yang memiliki salah satu karakter berikut: !#$%&'()*+/:<=>?@[]^`{|}mereka akan ditangani secara berbeda dengan perpustakaan itu. Jika Anda mengatur cookie, mereka dikodekan dengan %{HEX}. Dan jika Anda membaca cookie Anda harus memecahkan kode mereka.

Misalnya, meskipun email=name@domain.comcookie yang valid, pustaka ini akan menyandikannya sebagai email=name%40domain.com. Penguraian kode dapat menunjukkan masalah jika Anda menggunakan %cookie Anda. Itu akan hancur. Misalnya, cookie Anda yang dulu: secretagentlevel=50%007and50%006menjadi secretagentlevel=507and506. Itu kasus tepi, tetapi sesuatu yang perlu diperhatikan jika beralih perpustakaan.

Juga, di perpustakaan ini, cookie diatur dengan default path=/yang berarti mereka dikirim pada setiap permintaan url ke host.

Jika Anda ingin menyandikan atau mendekode sendiri nilai-nilai ini, Anda dapat menggunakan encodeURIComponentatau decodeURIComponent, masing-masing.


Referensi:


Informasi tambahan:


0

Yang pertama perlu membuat cookie (saya telah memasukkan token di dalam cookie sebagai contoh) dan kemudian mengaturnya sebagai respons. Untuk menggunakan cookie dengan cara berikut, instal cookieParser

app.use(cookieParser());

Browser akan menyimpannya di tab 'Sumber Daya' dan akan digunakan untuk setiap permintaan setelah itu mengambil URL awal sebagai basis

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

Untuk mendapatkan cookie dari permintaan di sisi server juga mudah. ​​Anda harus mengekstrak cookie dari permintaan dengan memanggil properti 'cookie' dari objek permintaan.

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

0

Jika Anda tidak peduli apa yang ada di cookiedalamnya dan Anda hanya ingin menggunakannya, coba pendekatan bersih ini dengan menggunakan request(modul simpul populer):

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

Maaf, tetapi kode ini sama sekali tidak masuk akal bagi saya. Apakah jar()beberapa nama metode imut untuk mendapatkan daftar cookie saat ini? Apa gunanya 2 permintaan permintaan? Ini sebagian besar merupakan iklan, bukan jawaban.
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

Menggunakan Beberapa ES5 / 6 Sihir & RegEx Magic

Berikut adalah opsi untuk membaca cookie dan mengubahnya menjadi objek Key, Pasangan nilai untuk sisi klien, juga dapat menggunakannya di sisi server.

Catatan : Jika ada =nilai, jangan khawatir. Jika ada =kunci, masalah di surga.

Lebih Banyak Catatan : Beberapa orang mungkin berpendapat keterbacaan jadi hancurkan sesuai keinginan.

Saya Suka Catatan : Menambahkan penangan kesalahan (coba tangkap) tidak ada salahnya.

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

masukkan deskripsi gambar di sini

Apa yang sedang terjadi?

iLikeCookies()akan membagi cookie dengan ;( spasi setelah; ):

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

Kemudian kami memetakan array itu dan membaginya dengan kemunculan pertama =menggunakan regex capturing parens :

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

Kemudian gunakan teman kita `Object.fromEntries untuk menjadikan ini objek kunci, pasangan val.

Suara


0

Saya menulis fungsi sederhana ini hanya lulus req.headers.cookiedan nama 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
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.