รับและตั้งค่าคุกกี้เดี่ยวพร้อมเซิร์ฟเวอร์ Node.js HTTP


159

ฉันต้องการที่จะสามารถตั้งค่าคุกกี้เดียวและอ่านคุกกี้เดียวกับคำขอแต่ละครั้งที่ทำกับอินสแตนซ์ของเซิร์ฟเวอร์ nodejs มันสามารถทำได้ในไม่กี่บรรทัดของรหัสโดยไม่ต้องดึง lib บุคคลที่สาม?

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 และทำงานเป็นคุกกี้

คำตอบ:


190

ไม่มีฟังก์ชั่นการเข้าถึงอย่างรวดเร็วในการรับ / ตั้งค่าคุกกี้ดังนั้นฉันจึงได้แฮ็คต่อไปนี้:

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

วิธีนี้จะเก็บคุกกี้ทั้งหมดไว้ในวัตถุคุกกี้และคุณต้องตั้งค่าคุกกี้เมื่อคุณเขียนหัว


11
รหัสดังกล่าวจะทำงานไม่ถูกต้องถ้าค่าของคุกกี้มีเท่ากับ ( =) เข้าสู่ระบบเป็นหนึ่งในคุกกี้ของ Facebook fbm_1234123412341234=base_domain=.domain.comเช่น
ตา

3
ค่าคุกกี้ไม่ต้องเข้ารหัส URL / เข้ารหัสร้อยละ = ในค่า doockie จะไม่ถูกต้องในกรณีนั้นใช่ไหม
les2

2
ในกรณีที่แยกจากแล้วโดยตัวอย่างแรกของ; =ด้านซ้ายคือกุญแจสำคัญคือค่า
iLoch

4
ฉันพบปัญหาเดียวกันกับ @Eye แทนที่จะไปตามเส้นทางของ @iLoch ฉันเปลี่ยนparts[0]ไปใช้parts.shift()และparts[1]ไปที่parts.join('=')
aron.duby

3
รหัสที่ให้มีข้อผิดพลาดร้ายแรงและผู้คนคัดลอกเพื่อคัดลอก ดูการปรับปรุงล่าสุดของฉัน
แดน

124

หากคุณใช้ไลบรารีด่วนเช่นเดียวกับผู้พัฒนา node.js มีวิธีที่ง่ายกว่า ตรวจสอบหน้าเอกสาร Express.js สำหรับข้อมูลเพิ่มเติม

ตัวอย่างการแยกวิเคราะห์ข้างต้นใช้งานได้อย่างชัดเจน แต่มีความชัดเจนช่วยให้คุณใช้งานได้ดี

app.use(express.cookieParser());

วิธีตั้งค่าคุกกี้:

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

วิธีล้างคุกกี้:

res.clearCookie('cookiename');

14
ไลบรารีคุกกี้นั้นมาจากการเชื่อมต่อกับไลบรารีพื้นฐาน คุณไม่จำเป็นต้องใช้ทุกอย่างในการรับผู้ช่วยคุกกี้
Ajax

1
จริงๆแล้วไลบรารีคุกกี้ไม่ได้เป็นส่วนหนึ่งของการเชื่อมต่อ (ซึ่งไม่สามารถตั้งค่าคุกกี้)
framp

10
cookie-parserไม่ได้เป็นส่วนหนึ่งของการเชื่อมต่อด่วนและ / หรือการเชื่อมต่อ แต่มีให้เป็นมิดเดิลแวร์: github.com/expressjs/cookie-parser
Koen

7
หนึ่ง "รับ" คุกกี้ในตัวอย่างนี้ได้อย่างไร เพื่อความสมบูรณ์และการตอบคำถาม
hubatish

1
Downvoting เนื่องจากต้องการติดตั้งด่วนเพียงใช้คุกกี้
Steven

34

RevNoah มีคำตอบที่ดีที่สุดกับข้อเสนอแนะของการใช้ด่วนของparser คุกกี้ แต่คำตอบนั้นตอนนี้อายุ 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"
  },

การดำเนินการเพิ่มเติมเช่นการตั้งค่าและการแยกคุกกี้อธิบายไว้ที่นี่ และที่นี่


8
คำถามถามว่าจะรับและตั้งค่าอย่างไร หากต้องการตั้งค่าให้ใช้:res.cookie('cookieName', cookieValue, { maxAge: 900000, httpOnly: true });
Augie Gardner

คุณสามารถตั้งค่าและรับคุกกี้แบบต่อเซสชันได้ (โดยไม่จำเป็นต้องรู้และจัดการคีย์)?
Matej J

12

เพื่อเป็นการปรับปรุงคำตอบของ @Corey Hart ฉันได้เขียนการparseCookies()ใช้ใหม่:

นี่คือตัวอย่างการทำงาน:

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

ฉันยังทราบว่า OP ใช้โมดูล http หาก OP กำลังใช้restifyเขาสามารถใช้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
ข้อเสนอแนะบางอย่างตอนนี้ 3.5 ปีต่อมาสำหรับผู้ชมในอนาคต ใช้let/constและstringifyCookiesสามารถเป็นหนึ่งเรียงรายไปด้วยmapแทนที่จะสร้างอาร์เรย์แบบนั้น
Ascherer

10

คุณสามารถใช้โมดูล "คุกกี้" npm ซึ่งมีชุดคุณสมบัติที่ครอบคลุม

เอกสารและตัวอย่างได้ที่:
https://github.com/jed/cookies


1
ดูเหมือนว่าโมดูลนั้นมีไว้สำหรับใช้ในเซิร์ฟเวอร์ http มีเครื่องมือ cookiejar สำหรับจัดการคุกกี้ในไคลเอนต์ http หรือไม่ โดยทั่วไปฉัน aant จะบอก lib ไคลเอนต์ http: หากคุณได้รับส่วนหัว Set-Cookie ใด ๆ ให้จดจำพวกเขาโดยอัตโนมัติแล้วส่งต่อคำขอขาออกที่ตามมาตามความเหมาะสม (เมื่อโดเมนตรงกับ)
Cheeso

นี่จะเป็นคุณสมบัติของไลบรารีไคลเอ็นต์ HTTP ที่คุณเลือก ฉันสามารถแนะนำsuperagentเป็นตัวอย่างที่ดี
Zah

เลิกพยายามทำให้ lib นี้ทำงานได้อย่างรวดเร็วหลังจากสองสามชั่วโมง ... ใช้การเชื่อมต่อแทน
enko

7

ในการรับตัวแยกคุกกี้เพื่อทำงานกับคุกกี้ที่มี '=' ในค่าคุกกี้:

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

จากนั้นรับคุกกี้แต่ละรายการ:

get_cookies(request)['my_cookie']


2

นี่คือแพทช์คัดลอก -n-paste ที่เรียบร้อยสำหรับการจัดการคุกกี้ในโหนด ฉันจะทำสิ่งนี้ใน 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

ตอนนี้คุณจะสามารถจัดการกับคุกกี้ได้อย่างที่คุณต้องการ:

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 นั้นไม่ใช่เรื่องยากที่จะอ่านถ้าคุณรู้จักจาวาสคริปต์
Mattijs

1

ให้ฉันทำซ้ำส่วนนี้ของคำถามที่คำตอบที่นี่ไม่สนใจ:

มันสามารถทำได้ในไม่กี่บรรทัดของรหัสโดยไม่ต้องดึง lib บุคคลที่สาม?


อ่านคุกกี้

คุกกี้จะถูกอ่านจากคำขอที่มีCookieส่วนหัว พวกเขารวมถึงและname valueเนื่องจากวิธีการทำงานของเส้นทางจึงสามารถส่งคุกกี้ที่มีชื่อเดียวกันหลายรายการได้ ใน NodeJS คุกกี้ทั้งหมดจะอยู่ในสตริงเดียวตามที่ถูกส่งในCookieส่วนหัว ;คุณสามารถแยกพวกเขาด้วย เมื่อคุณมีคุกกี้ทุกอย่างทางด้านซ้ายของเท่ากับ (ถ้ามี) เป็นและทุกอย่างเป็นหลังจากที่name valueเบราว์เซอร์บางตัวจะยอมรับคุกกี้ที่ไม่มีเครื่องหมายเท่ากับและเข้าใจชื่อว่าง ช่องว่างไม่นับเป็นส่วนหนึ่งของคุกกี้ สามารถห่อค่าด้วยเครื่องหมายคำพูดคู่ ( ") =ค่ายังสามารถมี ตัวอย่างเช่นformula=5+3=8เป็นคุกกี้ที่ถูกต้อง

/**
 * @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หากคุณมีความคาดหวังที่ซ้ำกันแล้วคุณต้องการจะทำย้ำผ่าน เบราว์เซอร์ฟีดคุกกี้ในลำดับความสำคัญจากมากไปน้อยดังนั้นการย้อนกลับทำให้แน่ใจว่าคุกกี้ลำดับความสำคัญสูงสุดปรากฏในวัตถุ ( .slice()คือเพื่อหลีกเลี่ยงการกลายพันธุ์ของอาร์เรย์)


การตั้งค่าคุกกี้

คุกกี้ "เขียน" ทำได้โดยใช้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);

จำไว้ว่าคุณสามารถตั้งค่าคุกกี้หลายรายการได้เพราะคุณสามารถตั้งค่าหลายSet-Cookieส่วนหัวได้ตามคำขอของคุณ นั่นเป็นเหตุผลว่าทำไมจึงเป็นอาร์เรย์


หมายเหตุเกี่ยวกับไลบรารีภายนอก:

หากคุณตัดสินใจที่จะใช้express, cookie-parserหรือcookieทราบว่าพวกเขามีค่าเริ่มต้นที่ไม่ได้มาตรฐาน คุกกี้ที่ถูกวิเคราะห์คำจะถูกถอดรหัส URI เสมอ (ถอดรหัสเป็นเปอร์เซ็นต์) ซึ่งหมายความว่าหากคุณใช้ชื่อหรือค่าที่มีอักขระใด ๆ ต่อไปนี้: !#$%&'()*+/:<=>?@[]^`{|}พวกเขาจะได้รับการจัดการแตกต่างจากไลบรารีเหล่านั้น %{HEX}หากคุณกำลังตั้งคุกกี้พวกเขาจะถูกเข้ารหัสด้วย และถ้าคุณอ่านคุกกี้คุณต้องถอดรหัสมัน

ยกตัวอย่างเช่นในขณะที่เป็นคุกกี้ที่ถูกต้องห้องสมุดเหล่านี้จะเข้ารหัสเป็นemail=name@domain.com email=name%40domain.comการถอดรหัสสามารถแสดงปัญหาได้หากคุณใช้%ในคุกกี้ของคุณ มันจะได้รับการ mangled ยกตัวอย่างเช่นคุกกี้ของคุณที่ได้รับ: กลายเป็นsecretagentlevel=50%007and50%006 secretagentlevel=507and506นั่นเป็นกรณีที่มีขอบ แต่มีบางสิ่งที่ควรทราบหากเปลี่ยนไลบรารี

นอกจากนี้ในไลบรารีเหล่านี้คุกกี้จะถูกตั้งค่าเป็นค่าเริ่มต้นpath=/ซึ่งหมายความว่ามีการส่งคุกกี้ทุกครั้งที่มีการร้องขอไปยังโฮสต์

หากคุณต้องการเข้ารหัสหรือถอดรหัสค่าเหล่านี้ด้วยตัวคุณเองคุณสามารถใช้encodeURIComponentหรือdecodeURIComponentตามลำดับ


อ้างอิง:


ข้อมูลเพิ่มเติม:


0

ก่อนอื่นต้องสร้างคุกกี้ (ฉันได้ห่อโทเค็นข้างในคุกกี้ไว้เป็นตัวอย่าง) แล้วตั้งเป็นคำตอบในการใช้คุกกี้ตามวิธีการติดตั้ง 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();

ในการรับคุกกี้จากคำขอทางฝั่งเซิร์ฟเวอร์ก็ง่ายเช่นกันคุณต้องแยกคุกกี้ออกจากคำขอโดยเรียกคุณสมบัติ 'คุกกี้' ของวัตถุคำขอ

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()บางชื่อวิธี cutesy ที่จะได้รับรายการปัจจุบันของคุกกี้หรือไม่ จุดประสงค์ของการร้องขอ 2 ข้อคืออะไร นี่เป็นโฆษณาส่วนใหญ่ไม่ใช่คำตอบ
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

ใช้เวทมนต์ ES5 / 6 และเวทมนตร์ RegEx

นี่คือตัวเลือกในการอ่านคุกกี้และเปลี่ยนเป็นวัตถุของคู่คีย์, ค่าสำหรับฝั่งไคลเอ็นต์, สามารถใช้ฝั่งเซิร์ฟเวอร์

หมายเหตุ : หากมี=ค่าในไม่ต้องกังวล หากมี=กุญแจอยู่ในปัญหาในสวรรค์

หมายเหตุเพิ่มเติม : บางคนอาจโต้แย้งว่าการอ่านได้ดังนั้นโปรดทำลายตามที่คุณต้องการ

ฉันชอบหมายเหตุ : การเพิ่มตัวจัดการข้อผิดพลาด (ลองจับ) จะไม่เจ็บ

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()จะแยกคุกกี้ด้วย;( เว้นวรรคหลัง; ):

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

จากนั้นเราแมปอาร์เรย์นั้นและแยกตามการเกิดขึ้นครั้งแรกของการ=ใช้เรนจ์จับภาพ regex :

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

จากนั้นใช้เพื่อนของเรา `วัตถุจากความพยายามที่จะทำให้สิ่งนี้เป็นวัตถุของคีย์คู่วาล

Nooice


0

ฉันเขียนฟังก์ชันง่าย ๆ นี้เพียงแค่ส่ง req.headers.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
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.