Nhận và đặt một cookie với máy chủ HTTP Node.js


159

Tôi muốn có thể đặt một cookie duy nhất và đọc cookie đơn đó với mỗi yêu cầu được gửi đến phiên bản máy chủ của nodejs. Nó có thể được thực hiện trong một vài dòng mã, mà không cần phải kéo vào một bên thứ ba 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/');

Chỉ cần cố gắng lấy mã ở trên trực tiếp từ nodejs.org và làm việc với cookie.

Câu trả lời:


190

Không có quyền truy cập chức năng nhanh để nhận / cài đặt cookie, vì vậy tôi đã đưa ra cách hack sau:

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

Điều này sẽ lưu trữ tất cả các cookie vào đối tượng cookie và bạn cần đặt cookie khi bạn viết phần đầu.


11
Mã ở trên sẽ hoạt động không chính xác nếu giá trị của cookie chứa dấu bằng ( =) như trong một trong các cookie của Facebook như thế nào fbm_1234123412341234=base_domain=.domain.com.
Mắt

3
không phải giá trị cookie phải được mã hóa URL / phần trăm được mã hóa? = trong giá trị doockie sẽ không hợp lệ trong trường hợp đó, phải không?
les2

2
Trong trường hợp đó được phân chia bởi ;sau đó bởi trường hợp đầu tiên của =. Trái là chìa khóa, phải là giá trị.
iLoch

4
Tôi chạy vào cùng một vấn đề như @Eye, thay vì đi theo con đường của @iLoch Tôi chuyển parts[0]đến parts.shift()parts[1]đểparts.join('=')
aron.duby

3
Các mã được đưa ra đã có lỗi nghiêm trọng và mọi người đã cố gắng sao chép nó. Xem cập nhật mới nhất của tôi
Dan

124

Nếu bạn đang sử dụng thư viện express, như nhiều nhà phát triển node.js làm, có một cách dễ dàng hơn. Kiểm tra trang tài liệu Express.js để biết thêm thông tin.

Ví dụ phân tích cú pháp ở trên hoạt động nhưng express cung cấp cho bạn một chức năng hay để xử lý việc đó:

app.use(express.cookieParser());

Để đặt cookie:

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

Để xóa cookie:

res.clearCookie('cookiename');

14
Thư viện cookie thực sự là từ thư viện cơ sở kết nối; bạn không cần phải nhận tất cả nhanh để có được người trợ giúp cookie.
Ajax

1
thực tế thư viện cookie không phải là một phần của kết nối (không thể đặt cookie)
framp

10
cookie-parserkhông còn là một phần của express và / hoặc kết nối, nhưng có sẵn dưới dạng phần mềm trung gian: github.com/expressjs/cookie-parser
Koen.

7
Làm thế nào để một "có được" một cookie trong ví dụ này? Để hoàn thiện và trả lời câu hỏi.
hubatish 16/07/2015

1
Tải xuống do cần cài đặt express chỉ để sử dụng cookie
Steven

34

RevNoah đã có câu trả lời tốt nhất với đề xuất sử dụng trình phân tích cú pháp cookie của Express . Nhưng, câu trả lời đó giờ đã 3 tuổi và đã lỗi thời.

Sử dụng Express , bạn có thể đọc cookie như sau

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

Và cập nhật của bạn package.jsonvới những điều sau đây, thay thế các phiên bản tương đối mới nhất.

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

Các hoạt động khác như cài đặt và phân tích cookie được mô tả ở đâyđây


8
Câu hỏi hỏi làm thế nào để có được thiết lập. Để cài đặt, hãy sử dụng:res.cookie('cookieName', cookieValue, { maxAge: 900000, httpOnly: true });
Augie Gardner

Bạn có thể thiết lập và nhận cookie dưới dạng một phiên (không cần biết và xử lý các khóa) không?
Matej J

12

Để cải thiện câu trả lời của @Corey Hart, tôi đã viết lại parseCookies()bằng cách sử dụng:

Đây là ví dụ hoạt động:

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

Tôi cũng lưu ý rằng OP sử dụng mô-đun http. Nếu OP đang sử dụng restify , anh ta có thể sử dụng 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
một số gợi ý bây giờ, 3,5 năm sau, cho người xem trong tương lai. Sử dụng let/conststringifyCookiescó thể được xếp thành một hàng mapthay vì xây dựng một mảng theo cách đó.
Ascherer

10

Bạn có thể sử dụng mô-đun npm "cookies", có một bộ tính năng toàn diện.

Tài liệu và ví dụ tại:
https://github.com/jed/cookies


1
Có vẻ như mô-đun đó được thiết kế để sử dụng trong các máy chủ http. Có một công cụ cookiejar để xử lý cookie trong http client? Về cơ bản tôi không muốn nói với lib client http: nếu bạn nhận được bất kỳ tiêu đề Set-Cookie nào, hãy tự động nhớ chúng và sau đó chuyển các yêu cầu gửi đi tiếp theo nếu phù hợp (khi tên miền khớp).
Cheeso

Đây sẽ là một tính năng của thư viện khách hàng http của bạn lựa chọn. Tôi có thể đề nghị superagent là một ví dụ tốt.
zah

Đã cố gắng để làm cho lib này hoạt động nhanh sau vài giờ ... sử dụng kết nối thay thế.
enko

7

Để có bộ chia cookie hoạt động với các cookie có '=' trong các giá trị 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;
};

sau đó để có được một cookie riêng lẻ:

get_cookies(request)['my_cookie']


2

Đây là một bản vá sao chép-n-dán gọn gàng để quản lý cookie trong nút. Tôi sẽ làm điều này trong CoffeeScript, vì vẻ đẹp.

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

Bây giờ bạn sẽ có thể xử lý cookie như bạn mong đợi:

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
Chỉ cần sao chép mã đó trong tab TRY COFFESCRIPT trên coffeescript.org . Câu trả lời của bạn đã giúp tôi và coffeescript không khó đọc nếu bạn biết javascript.
Mattijs

1

Hãy để tôi nhắc lại phần câu hỏi mà câu trả lời ở đây đang bỏ qua:

Nó có thể được thực hiện trong một vài dòng mã, mà không cần phải kéo vào một bên thứ ba lib?


Đọc bánh quy

Cookies được đọc từ các yêu cầu với Cookietiêu đề. Chúng chỉ bao gồm một namevalue. Do cách thức hoạt động của đường dẫn, nhiều cookie cùng tên có thể được gửi. Trong NodeJS, tất cả Cookies trong một chuỗi khi chúng được gửi trong Cookietiêu đề. Bạn chia chúng với ;. Khi bạn có cookie, mọi thứ ở bên trái của bằng (nếu có) là namevà mọi thứ sau đó là value. Một số trình duyệt sẽ chấp nhận cookie không có dấu bằng và giả sử tên trống. Whitespaces không được tính là một phần của cookie. Các giá trị cũng có thể được gói trong dấu ngoặc kép ( "). Các giá trị cũng có thể chứa =. Ví dụ, formula=5+3=8là một cookie hợp lệ.

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

Nếu bạn không mong đợi các tên trùng lặp, thì bạn có thể chuyển đổi thành một đối tượng giúp mọi việc dễ dàng hơn. Sau đó, bạn có thể truy cập như object.myCookieNameđể có được giá trị. Nếu bạn đang mong đợi các bản sao, thì bạn muốn lặp đi lặp lại cookieEntries. Trình duyệt cung cấp cookie theo mức độ ưu tiên giảm dần, do đó việc đảo ngược đảm bảo cookie có mức độ ưu tiên cao nhất xuất hiện trong đối tượng. (Đây .slice()là để tránh đột biến của mảng.)


Cài đặt cookie

"Viết" cookie được thực hiện bằng cách sử dụng Set-Cookietiêu đề trong phản hồi của bạn. Đối response.headers['Set-Cookie']tượng thực sự là một mảng, vì vậy bạn sẽ đẩy nó. Nó chấp nhận một chuỗi nhưng có nhiều giá trị hơn chỉ namevalue. Phần khó nhất là viết chuỗi, nhưng điều này có thể được thực hiện trong một dòng.

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

Hãy nhớ rằng bạn có thể đặt nhiều cookie, vì thực tế bạn có thể đặt nhiều Set-Cookietiêu đề trong yêu cầu của mình. Đó là lý do tại sao nó là một mảng.


Lưu ý về các thư viện bên ngoài:

Nếu bạn quyết định sử dụng express, cookie-parserhoặc cookie, lưu ý họ có giá trị mặc định mà không chuẩn. Cookie được phân tích cú pháp luôn được giải mã URI (phần trăm được giải mã). Điều đó có nghĩa là nếu bạn sử dụng tên hoặc giá trị có bất kỳ ký tự nào sau đây: !#$%&'()*+/:<=>?@[]^`{|}chúng sẽ được xử lý khác nhau với các thư viện đó. Nếu bạn đang đặt cookie, chúng được mã hóa bằng%{HEX} . Và nếu bạn đang đọc cookie, bạn phải giải mã chúng.

Ví dụ, trong khi email=name@domain.comlà một cookie hợp lệ, các thư viện này sẽ mã hóa nó dưới dạng email=name%40domain.com. Giải mã có thể thể hiện các vấn đề nếu bạn đang sử dụng %trong cookie của mình. Nó sẽ bị hỏng. Ví dụ: cookie của bạn là: secretagentlevel=50%007and50%006trở thànhsecretagentlevel=507and506 . Đó là một trường hợp cạnh, nhưng một điều cần lưu ý nếu chuyển đổi thư viện.

Ngoài ra, trên các thư viện này, cookie được đặt mặc định path=/có nghĩa là chúng được gửi trên mỗi yêu cầu url đến máy chủ lưu trữ.

Nếu bạn muốn tự mã hóa hoặc giải mã các giá trị này, bạn có thể sử dụng encodeURIComponenthoặc decodeURIComponent, tương ứng.


Người giới thiệu:


Thông tin thêm:


0

Trước tiên, người ta cần tạo cookie (tôi đã bọc mã thông báo bên trong cookie làm ví dụ) và sau đó đặt nó trong phản hồi. Để sử dụng cookie theo cách sau đây cài đặt cookieParser

app.use(cookieParser());

Trình duyệt sẽ lưu nó trong tab 'Tài nguyên' và sẽ được sử dụng cho mọi yêu cầu sau đó lấy URL ban đầu làm cơ sở

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

Để nhận cookie từ một yêu cầu ở phía máy chủ cũng dễ dàng. Bạn phải trích xuất cookie từ yêu cầu bằng cách gọi thuộc tính 'cookie' của đối tượng yêu cầu.

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

0

Nếu bạn không quan tâm đến những gì trong cookievà bạn chỉ muốn sử dụng nó, hãy thử phương pháp sạch này bằng cách sử dụng request(một mô-đun nút phổ biến):

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

Xin lỗi, nhưng mã này không có ý nghĩa gì với tôi. Là jar()một số tên phương thức dễ thương để có được danh sách cookie hiện tại? Điểm của 2 yêu cầu là gì? Đây chủ yếu là một quảng cáo, không phải là một câu trả lời.
dùng1944491

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

Sử dụng một số phép thuật ES5 / 6 & RegEx Magic

Dưới đây là một tùy chọn để đọc cookie và biến chúng thành một đối tượng của các cặp Khóa, Giá trị cho phía máy khách, cũng có thể sử dụng phía máy chủ.

Lưu ý : Nếu có một =giá trị, không phải lo lắng. Nếu có một =chìa khóa, rắc rối trên thiên đường.

Ghi chú thêm : Một số có thể tranh luận khả năng đọc để phá vỡ nó như bạn muốn.

Tôi thích ghi chú : Thêm một trình xử lý lỗi (thử bắt) sẽ không bị tổn thương.

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

nhập mô tả hình ảnh ở đây

Chuyện gì đang xảy ra vậy?

iLikeCookies()sẽ phân chia cookie theo ;( khoảng trắng sau; ):

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

Sau đó, chúng tôi ánh xạ mảng đó và phân chia bằng lần xuất hiện đầu tiên của =việc sử dụng regex chụp parens :

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

Sau đó, sử dụng người bạn `Object.fromEntries của chúng tôi để biến điều này thành một đối tượng của các cặp khóa, val.

Không.


0

Tôi đã viết chức năng đơn giản này chỉ cần vượt qua req.headers.cookietên 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
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.