让我重复问题的这一部分,这里的答案被忽略:
是否可以通过几行代码来完成,而无需引入第三方库?
阅读饼干
从带有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,因此反转可确保优先级最高的cookie出现在对象中。(这.slice()
是为了避免数组发生突变。)
设定Cookie
通过Set-Cookie
在响应中使用标头来完成“编写” cookie 。该response.headers['Set-Cookie']
对象实际上是一个数组,因此您将使用它。它接受字符串,但具有比just 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}
。而且,如果您正在读取Cookie,则必须对其进行解码。
例如,虽然email=name@domain.com
是有效的Cookie,但这些库会将其编码为email=name%40domain.com
。如果您%
在Cookie 中使用,解码可能会出现问题。它会被扭曲。例如,您的Cookie原来是:secretagentlevel=50%007and50%006
变成secretagentlevel=507and506
。这是一个极端的情况,但是在切换库时要注意一点。
同样,在这些库上,cookie设置为默认值path=/
,这意味着它们会在每个url请求上发送到主机。
如果您想自己编码或解码这些值,可以分别使用encodeURIComponent
或decodeURIComponent
。
参考文献:
附加信息:
=
Facebook的其中一种cookie中的等号(),则上述代码将无法正常工作fbm_1234123412341234=base_domain=.domain.com
。