Отримайте та встановіть єдиний файл cookie за допомогою сервера NTP.js HTTP


159

Я хочу мати змогу встановити один cookie та прочитати цей єдиний файл cookie з кожним запитом, зробленим до екземпляра сервера nodejs. Чи можна це зробити за допомогою декількох рядків коду, без необхідності втягувати сторонні вкладки?

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

Просто намагаюся взяти вищевказаний код безпосередньо з nodejs.org і запрацювати в ньому файл cookie.

Відповіді:


190

Немає швидкого доступу до функції для отримання / налаштування файлів cookie, тому я придумав такий злом:

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

Це дозволить зберегти всі файли cookie в об’єкт cookie, і вам потрібно встановити файли cookie, коли ви пишете голову.


11
Вищевказаний код буде працювати неправильно, якщо значення файлу cookie містить знак рівності ( =), як в одному з файлів cookie Facebook fbm_1234123412341234=base_domain=.domain.com.
Око

3
чи не повинні значення файлів cookie бути кодованими URL / відсотками? = у значенні doockie було б недійсно в цьому випадку, правда?
les2

2
У цьому випадку розділити на ;потім першою інстанцією =. Зліва - ключ, право - значення.
iLoch

4
Я зіткнувся з тією ж проблемою , як @Eye, замість того , щоб йти шляхом @iLoch I перейшов parts[0]до parts.shift()і parts[1]доparts.join('=')
aron.duby

3
У наведеному коді були серйозні помилки, і люди припинили його копіювати. Дивіться моє останнє оновлення
День

124

Якщо ви використовуєте експрес-бібліотеку, як це роблять багато розробників node.js, є простіший спосіб. Перегляньте сторінку документації Express.js для отримання додаткової інформації.

Приклад розбору, наведений вище, працює, але express дає вам гарну функцію, щоб подбати про це:

app.use(express.cookieParser());

Щоб встановити файл cookie:

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

Щоб очистити файл cookie:

res.clearCookie('cookiename');

14
Бібліотека файлів cookie насправді з базової підключення бібліотеки; вам не потрібно брати весь експрес, щоб отримати помічника у файлах cookie.
Аякс

1
насправді бібліотека файлів cookie не є частиною підключення (яка не може встановити файли cookie)
framp

10
cookie-parserбільше не є частиною експрес та / або підключення, але доступна як середнє
Koen.

7
Як в цьому прикладі можна "отримати" файли cookie? Для повноти та відповіді на запитання.
hubatish

1
Відхилення через необхідність встановлення експрес просто для використання файлів cookie
Стівен

34

RevNoah отримав найкращу відповідь із пропозицією використовувати аналізатор файлів cookie Express . Але ця відповідь вже 3 роки і застаріла.

Використовуючи Express , ви можете прочитати печиво наступним чином

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

І оновіть package.jsonнаступні, замінюючи відповідні відносно новіші версії.

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

Більше операцій, таких як встановлення та аналіз файлів cookie, описано тут і тут


8
Питання задає питання, як отримати та встановити. Щоб встановити, скористайтеся цим:res.cookie('cookieName', cookieValue, { maxAge: 900000, httpOnly: true });
Augie Gardner

Чи можете ви встановлювати та отримувати файли cookie як сеанс (без необхідності знати та обробляти ключі)?
Matej J

12

На додаток до відповіді @Corey Hart я переписав parseCookies():

  • RegExp.prototype.exec - використовуйте регулярний вираз для розбору рядків "name = value"

Ось робочий приклад:

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

Також зазначу, що в ОП використовується модуль http. Якщо ОП використовував restify , він може скористатися файлами cookie 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
деякі пропозиції зараз, через 3,5 роки, для майбутніх глядачів. Використовуйте let/constта stringifyCookiesможе бути вишикуватися mapзамість того, щоб будувати масив таким чином.
Ascherer

10

Можна використовувати npm-модуль "cookies", який має вичерпний набір функцій.

Документація та приклади за адресою:
https://github.com/jed/cookies


1
Схоже, цей модуль призначений для використання в http-серверах. Чи є інструмент cookiejar для обробки файлів cookie у клієнтів http? В основному я не можу повідомити http lib client lib: якщо ви отримаєте будь-які заголовки Set-Cookie, запам'ятайте їх автоматично, а потім передайте наступні вихідні запити у відповідних випадках (коли домен збігається).
Cheeso

Це буде особливістю вашої бібліотеки клієнтів на вибір. Я можу запропонувати суперагент як хороший приклад.
захід

Встановіть спробу змусити цю ліб працювати експресно через пару годин ... замість цього використовуйте connect.
enko

7

Щоб отримати роздільник файлів cookie для роботи з файлами cookie, у яких значення '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;
};

потім отримати індивідуальне cookie:

get_cookies(request)['my_cookie']


2

Ось акуратний патч копіювання-n-вставки для управління файлами cookie у вузлі. Я зроблю це в CoffeeScript, для краси.

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

Тепер ви зможете обробляти файли cookie так, як ви очікували:

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
Просто скопіюйте вставте цей код на вкладку TRY COFFESCRIPT на coffeescript.org . Ваша відповідь мені допомогла, і coffeescript не так важко читати, якщо ви знаєте JavaScript.
Маттійс

1

Дозвольте повторити цю частину запитання, на яку тут відповіді ігноруються:

Чи можна це зробити за допомогою декількох рядків коду, без необхідності втягувати сторонні вкладки?


Читання файлів cookie

Файли cookie читаються з запитів із Cookieзаголовком. Вони включають лише nameта value. Через те, як працюють шляхи, можна надсилати кілька однойменних файлів cookie. У NodeJS всі файли cookie в одному рядку, оскільки вони надсилаються у Cookieзаголовку. Ви розділите їх ;. Після отримання файлу cookie все ліворуч від рівних (якщо є) - це те name, а все після - це value. Деякі веб-переглядачі прийматимуть файл cookie без знака рівності та вважатимуть ім'я порожнім. Пробіли не враховуються як частина файлу cookie. Значення також можна загорнути у подвійні лапки ( "). Значення також можуть містити =. Наприклад, formula=5+3=8є дійсним файлом 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());

Якщо ви не очікуєте дублювання імен, ви можете перетворити його на об'єкт, що полегшує справи. Тоді ви можете отримати доступ як, object.myCookieNameщоб отримати значення. Якщо ви очікуєте дублікатів, тоді ви хочете зробити повторення cookieEntries. Браузери подають файли cookie у зменшенні пріоритету, тому реверсування забезпечує печиво з найвищим пріоритетом у об’єкті. (Це .slice()уникнути мутації масиву.)


Налаштування cookie

"Написання" файлів cookie здійснюється за допомогою Set-Cookieзаголовка у вашій відповіді. response.headers['Set-Cookie']Об'єкт насправді масив, так що ви будете штовхаючи до нього. Він приймає рядок, але має більше значень, ніж просто nameта value. Найважча частина - це написання рядка, але це можна зробити в одному рядку.

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

Пам'ятайте, що ви можете встановити кілька файлів cookie, оскільки ви можете фактично встановити кілька Set-Cookieзаголовків у своєму запиті. Ось чому це масив.


Примітка щодо зовнішніх бібліотек:

Якщо ви вирішили використовувати express, cookie-parserабо cookie, зверніть увагу , що вони мають значення по замовчуванням , які є нестандартними. Файли cookie, розібрані завжди, URI декодуються (відсотків розшифровуються). Це означає, що якщо ви використовуєте ім’я або значення, яке має будь-який з наступних символів: !#$%&'()*+/:<=>?@[]^`{|}вони будуть оброблятися по-різному з цими бібліотеками. Якщо ви встановлюєте файли cookie, вони кодуються %{HEX}. І якщо ви читаєте печиво, вам потрібно їх розшифрувати.

Наприклад, хоча email=name@domain.comце допустимий файл cookie, ці бібліотеки будуть кодувати його як email=name%40domain.com. Розшифрування може викликати проблеми, якщо ви використовуєте %файл cookie. Це заблукає. Наприклад, ваше печиво, яке було: secretagentlevel=50%007and50%006стає secretagentlevel=507and506. Це крайній випадок, але щось слід зазначити, якщо перемикати бібліотеки.

Також у цих бібліотеках файли cookie встановлюються за замовчуванням, path=/що означає, що вони надсилаються на кожен запит URL хосту.

Якщо ви хочете самостійно кодувати або декодувати ці значення, ви можете використовувати encodeURIComponentабо decodeURIComponent, відповідно.


Список літератури:


Додаткова інформація:


0

Спершу потрібно створити cookie (я запечатав маркер всередині cookie як приклад), а потім встановити його у відповідь. Щоб використовувати файл cookie наступним чином, встановіть cookieParser

app.use(cookieParser());

Веб-переглядач збереже його на вкладці "Ресурс" і використовуватиметься для кожного запиту, після чого береться початкова URL-адреса за основу

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

Отримати файл cookie із запиту на стороні сервера теж просто. Вам потрібно витягти файл cookie з запиту, зателефонувавши у властивість 'cookie' об’єкта запиту.

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

0

Якщо вам все одно, що в ньому, cookieі ви просто хочете його використовувати, спробуйте цей чистий підхід, використовуючи request(популярний модуль вузла):

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

Вибачте, але цей код для мене взагалі не має сенсу. Чи є jar()якесь ім'я методу милості, щоб отримати поточний список файлів cookie? Який сенс у двох викликах запиту? Це здебільшого реклама, а не відповідь.
користувач1944491

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

Використання деяких ES5 / 6 чаклунства та RegEx Magic

Тут є можливість прочитати файли cookie та перетворити їх на об'єкт Key, пары значень для клієнтської сторони, також можна використовувати його на стороні сервера.

Примітка : Якщо =значення є, не хвилюйтеся. Якщо =в ключі є, в раю біда.

Більше приміток : Деякі можуть стверджувати, що читабельність так розбивається, як вам подобається.

Мені подобаються нотатки : Додавання обробника помилок (спробуйте виловити) не завадило б.

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

введіть тут опис зображення

Що відбувається?

iLikeCookies()розділить файли cookie на ;( пробіл після; ):

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

Тоді ми відображаємо цей масив і розбиваємо за першим появою =використання регулярного вилучення паронів :

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

Потім використовуйте наш друг `Object.fromEntries, щоб зробити це об'єктом ключових, валь-пар.

Нукіс.


0

Я написав цю просту функцію просто пройти req.headers.cookieі ім'я файлу 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
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.