Get and Set a Single Cookie with Node.js HTTP Server
我希望能够设置一个cookie,并在对nodejs服务器实例的每个请求中读取该cookie。 是否可以通过几行代码来完成,而无需引入第三方库?
1 2 3 4 5 6 7 8 9 | var http = require('http'); http.createServer(function (request, response) { response.writeHead(200, {'Content-Type': 'text/plain'}); response.end('Hello World\ '); }).listen(8124); console.log('Server running at http://127.0.0.1:8124/'); |
只是尝试直接从nodejs.org中获取上述代码,然后在其中工作一个cookie。
无法快速获取/设置Cookie的功能,因此我想到了以下技巧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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\ '); }).listen(8124); console.log('Server running at http://127.0.0.1:8124/'); |
这会将所有cookie存储到cookie对象中,并且在编写头部时需要设置cookie。
如果您使用Express库,就像许多node.js开发人员一样,则有一种更简单的方法。查看Express.js文档页面以获取更多信息。
上面的解析示例有效,但是express给您提供了一个很好的函数来解决这一问题:
1 | app.use(express.cookieParser()); |
设置Cookie:
1 | res.cookie('cookiename', 'cookievalue', { maxAge: 900000, httpOnly: true }); |
清除Cookie:
1 | res.clearCookie('cookiename'); |
RevNoah对于使用Express的cookie解析器的建议是最好的答案。但是,这个答案现在已经3年了,已经过时了。
使用Express,您可以按以下方式读取Cookie
1 2 3 4 5 6 7 | 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']); }) |
并用以下内容更新您的
1 2 3 4 | "dependencies": { "express":"4.12.3", "cookie-parser":"1.4.0" }, |
此处介绍了更多操作,例如设置和解析Cookie
和这里
为了增强@Corey Hart的答案,我使用以下命令重写了
- RegExp.prototype.exec-使用正则表达式解析"名称=值"字符串
这是工作示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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\ '); } ).listen(1234); |
我还注意到OP使用http模块。
如果OP使用restify,则他可以使用restify-cookie:
1 2 3 4 5 6 7 8 9 10 | 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); |
您可以使用" cookies" npm模块,该模块具有一组全面的功能。
文档和示例,请访问:
https://github.com/jed/cookies
要使Cookie拆分器与Cookie值中包含" ="的Cookie一起使用,请执行以下操作:
1 2 3 4 5 6 7 8 | 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:
1 | get_cookies(request)['my_cookie'] |
Cookie通过HTTP标头传输
您只需要解析请求标头并放入响应标头。
这是一个用于在节点中管理cookie的整洁的复制粘贴粘贴补丁。为了美观,我将在CoffeeScript中进行此操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 |
让我重复问题的这一部分,这里的答案被忽略:
Can it be done in a few lines of code, without the need to pull in a third party lib?
阅读饼干
从具有
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | /** * @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()); |
如果您不希望出现重复的名称,则可以将其转换为使事情变得更容易的对象。然后,您可以像
设定Cookie
通过在响应中使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | /** * @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,因为实际上您可以在请求中设置多个
关于外部库的注意事项:
如果决定使用
例如,虽然
同样,在这些库上,cookie设置为默认值
如果要自己编码或解码这些值,可以分别使用
参考文献:
- Cookie语法
- Set-Cookie语法
附加信息:
- https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Cookie
- https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Set-Cookie
我写了这个简单的函数
1 2 3 4 5 6 7 8 9 10 11 | const getCookieByName =(cookies,name)=>{ const arrOfCookies = cookies.split(' ') let yourCookie = null arrOfCookies.forEach(element => { if(element.includes(name)){ yourCookie = element.replace(name+'=','') } }); return yourCookie } |
使用一些ES5 / 6魔法和RegEx Magic
这是一个读取cookie并将其转换为Key对象的选项,客户端的值对也可以在服务器端使用。
注意:如果该值中包含
更多说明:有些人可能会争辩可读性,因此请根据需要对其进行分解。
我喜欢注释:添加错误处理程序(尝试捕获)不会有问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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}`) } |
到底是怎么回事?
1 | ["name=Cookie Monster","likesCookies=yes=withARandomEquals"] |
然后,我们映射该数组,并使用正则表达式捕获parens按第一次出现的
然后使用我们的朋友`Object.fromEntries使其成为键,val对的对象。
Nooice。
如果您不在乎
1 2 3 4 5 6 7 8 9 | 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 }); }); |
首先需要创建cookie(我将令牌包装在cookie中作为示例),然后进行响应设置。要以以下方式使用cookie,请安装cookieParser
1 | app.use(cookieParser()); |
浏览器会将其保存在其"资源"标签中,并将随后的每个请求(以初始URL为基础)用于每个请求
1 2 3 4 5 | var token = student.generateToken('authentication'); res.cookie('token', token, { expires: new Date(Date.now() + 9999999), httpOnly: false }).status(200).send(); |
从服务器端的请求中获取cookie也是很容易的。您必须通过调用请求对象的'cookie'属性来从请求中提取cookie。
1 | var token = req.cookies.token; // Retrieving Token stored in cookies |
1 2 3 4 5 6 7 8 | 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); } |