使用Node.js HTTP Server获取并设置单个Cookie

Cor*_*art 149 javascript cookies node.js

我希望能够设置一个cookie,并在每次向nodejs服务器实例发出请求时读取该cookie.可以用几行代码完成,而不需要引入第三方库吗?

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/');
Run Code Online (Sandbox Code Playgroud)

只是尝试直接从nodejs.org获取上述代码,并在其中处理cookie.

Cor*_*art 182

获取/设置cookie没有快速功能访问,所以我想出了以下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/');
Run Code Online (Sandbox Code Playgroud)

这会将所有cookie存储到cookie对象中,并且在编写头部时需要设置cookie.

  • 如果cookie的值包含一个等于('=')符号如Facebook的饼干等`fbm_1234123412341234 = BASE_DOMAIN = .domain.com`之一上面的代码将不正确地工作. (9认同)
  • 我遇到了与@Eye相同的问题,而不是走@iLoch的路线我将`parts [0]`切换到`parts.shift()`和`parts [1]`转换为`parts.join('=' )` (4认同)
  • 不要cookie值必须是URL编码/百分比编码?=在这种情况下,在doockie值中是无效的,对吧? (3认同)
  • 给出的代码有严重的错误,人们不得不复制它.查看我的上次更新 (3认同)
  • 在那种情况下,由`;`分割,然后由`=`的第一个实例分割.左是关键,右是价值. (2认同)

Rev*_*oah 119

如果你正在使用快速库,就像许多node.js开发人员那样,有一种更简单的方法.有关更多信息,请查看Express.js文档页面.

上面的解析示例有效,但express给你一个很好的功能来处理:

app.use(express.cookieParser());
Run Code Online (Sandbox Code Playgroud)

要设置cookie:

res.cookie('cookiename', 'cookievalue', { maxAge: 900000, httpOnly: true });
Run Code Online (Sandbox Code Playgroud)

要清除cookie:

res.clearCookie('cookiename');
Run Code Online (Sandbox Code Playgroud)

  • 这些评论举例说明了clusterf***express已经变成了多少. (18认同)
  • cookie库实际上来自底层库连接; 你不需要全部快递来获得cookie助手. (13认同)
  • `cookie-parser`不再是express和/或connect的一部分,但可以作为中间件使用:https://github.com/expressjs/cookie-parser (10认同)
  • 在这个例子中,如何"获得"一个cookie?为了完整性和回答问题. (6认同)
  • 由于需要安装 Express 才能使用 cookie,因此投了反对票 (2认同)

Kir*_*rby 31

对于使用Express的cookie解析器的建议,RevNoah得到了最好的答案.但是,这个答案现在已经过了3年,已经过时了.

使用Express,您可以按如下方式阅读cookie

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']);
})
Run Code Online (Sandbox Code Playgroud)

package.json使用以下内容更新您的内容,替换相应的相对最新版本.

"dependencies": {
    "express": "4.12.3",
    "cookie-parser": "1.4.0"
  },
Run Code Online (Sandbox Code Playgroud)

此处描述更多操作,如设置和解析cookie

  • 问题是如何设置__and__.设置使用:`res.cookie('cookieName',cookieValue,{maxAge:900000,httpOnly:true});` (5认同)
  • 对一个问题的很多基于快速的答案,显示了使用普通 Node http 模块的代码...... (3认同)

zah*_*zah 10

您可以使用"cookies"npm模块,它具有一整套功能.

文档和示例:https:
//github.com/jed/cookies


Ste*_*uan 9

作为@Corey Hart答案的增强,我改写了parseCookies()使用:

这是工作示例:

let http = require('http');

function parseCookies(cookie) {
  let rx = /([^;=\s]*)=([^;]*)/g;
  let obj = { };
  for ( let m ; m = rx.exec(cookie) ; )
    obj[ m[1] ] = decodeURIComponent( m[2] );
  return obj;
}

function stringifyCookies(cookies) {
  let list = [ ];
  for ( [ key, value ] of Object.entries( cookies ) )
    list.push( key + '=' + encodeURIComponent( value ) );
  return list.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);
Run Code Online (Sandbox Code Playgroud)

我还注意到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);
Run Code Online (Sandbox Code Playgroud)


Tob*_* P. 6

Cookie 通过HTTP-Header传输
您只需要解析请求标头并放置响应标头.


Dav*_*ith 6

要使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;
};
Run Code Online (Sandbox Code Playgroud)

然后获得一个单独的cookie:

get_cookies(request)['my_cookie']
Run Code Online (Sandbox Code Playgroud)


Sho*_*use 6

让我重复一下这里的答案忽略的这部分问题:

可以用几行代码完成,而不需要拉入第三方库吗?


读取饼干

Cookie 是从带有Cookie标头的请求中读取的。它们只包括一个namevalue。由于路径的工作方式,可以发送多个同名的 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());
Run Code Online (Sandbox Code Playgroud)

如果您不希望有重复的名称,那么您可以转换为一个对象,这让事情变得更容易。然后你可以访问 likeobject.myCookieName来获取值。如果您期望重复,那么您想要遍历cookieEntries. 浏览器以降序提供 cookie,因此反向确保最高优先级的 cookie 出现在对象中。(这.slice()是为了避免数组的突变。)


设置 Cookie

“写入”cookie 是通过Set-Cookie在响应中使用标头来完成的。该response.headers['Set-Cookie']对象实际上是一个数组,因此您将对其进行推送。它接受一个字符串,但具有比nameand更多的值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);
Run Code Online (Sandbox Code Playgroud)

请记住,您可以设置多个 cookie,因为您实际上可以Set-Cookie在请求中设置多个标头。这就是为什么它是一个数组。


关于外部库的注意事项:

如果你决定使用expresscookie-parser或者cookie,请注意他们是非标准的默认值。解析的 Cookie 总是 URI 解码(百分比解码)。这意味着如果您使用具有以下任何字符的名称或值:!#$%&'()*+/:<=>?@[]^`{|}这些库将对其进行不同的处理。如果您正在设置 cookie,它们将使用%{HEX}. 如果您正在阅读 cookie,则必须对其进行解码。

例如,虽然email=name@domain.com是有效的 cookie,但这些库会将其编码为email=name%40domain.com. 如果您%在 cookie中使用 ,则解码可能会出现问题。它会被破坏。例如,您的 cookie 是:secretagentlevel=50%007and50%006变为secretagentlevel=507and506。这是一个边缘情况,但如果切换库需要注意。

此外,在这些库上,cookie 设置为默认值path=/,这意味着它们会在每个 url 请求时发送到主机。

如果您想自己编码或解码这些值,可以分别使用encodeURIComponentdecodeURIComponent


参考:


附加信息: