HTTP 請(qǐng)求都是無(wú)狀態(tài)的窒百,但是我們的 Web 應(yīng)用通常都需要知道發(fā)起請(qǐng)求的人是誰(shuí)矗烛。為了解決這個(gè)問(wèn)題,HTTP 協(xié)議設(shè)計(jì)了一個(gè)特殊的請(qǐng)求頭:Cookie。服務(wù)端可以通過(guò)響應(yīng)頭(set-cookie)將少量數(shù)據(jù)響應(yīng)給客戶端咖气,瀏覽器會(huì)遵循協(xié)議將數(shù)據(jù)保存月而,并在下次請(qǐng)求同一個(gè)服務(wù)的時(shí)候帶上(瀏覽器也會(huì)遵循協(xié)議汗洒,只在訪問(wèn)符合 Cookie 指定規(guī)則的網(wǎng)站時(shí)帶上對(duì)應(yīng)的 Cookie 來(lái)保證安全性)。
Cookies
Cookies 的作用
- 同一個(gè)瀏覽器訪問(wèn)同一個(gè)域的時(shí)候父款,不同頁(yè)面之間的數(shù)據(jù)共享溢谤。
- 數(shù)據(jù)持久化瞻凤。(關(guān)閉瀏覽器后重新打開(kāi)瀏覽器頁(yè)面,數(shù)據(jù)還存在)世杀。
Egg.js 中 Cookie 的設(shè)置和獲取
Cookie 設(shè)置語(yǔ)法:ctx.cookies.set(key, value, options)
this.ctx.cookies.set('name','Andy');
Cookie 獲取語(yǔ)法:ctx.cookies.get(key, options)
this.ctx.cookies.get('name');
示例代碼
在響應(yīng)某一個(gè) HTML 頁(yè)面時(shí)阀参,設(shè)置 Cookies:
'use strict';
const Controller = require('egg').Controller;
class HomeController extends Controller {
async index() {
/*
* ??????
* 設(shè)置 cookies
* ctx.cookies.set(key, value, options)
* 參數(shù):
* key : cookies 的名稱
* value : cookies 的值
* optons : 配置
*/
this.ctx.cookies.set('username', 'Andy', {
maxAge: 1000 * 3600 * 24, // cookies 有效期:一天
httpOnly: true,
signed: true, // 對(duì) Cookies 進(jìn)行簽名,防止用戶修改
encrypt: true, // 對(duì) Cookies 進(jìn)行加密瞻坝,同時(shí)獲取時(shí)ye需要解密
});
// 顯示表單頁(yè)面蛛壳,加載并渲染 HTML 模版文件
// this.ctx.csrf 用戶訪問(wèn)頁(yè)面時(shí)生成的密鑰
await this.ctx.render('home');
}
}
module.exports = HomeController;
然后打開(kāi)其他頁(yè)面時(shí),可以獲取這個(gè)頁(yè)面中設(shè)置的 Cookies:
'use strict';
const Controller = require('egg').Controller;
class NewsController extends Controller {
// 獲取數(shù)據(jù)顯示到新聞頁(yè)面
async index() {
// ?????? 獲取 cookies 值
const userinfo = this.ctx.cookies.get('username', {
encrypt: true, // 對(duì)被加密的 Cookies 進(jìn)行解密
});
console.log(userinfo);
// 調(diào)用 Service 層方法
const listInfo = await this.service.news.getNewsList();
// 渲染模版引擎
await this.ctx.render('news', { list: listInfo });
}
}
module.exports = NewsController;
其他問(wèn)題
-
如何持久化存儲(chǔ) Cookies湿镀?
默認(rèn)情況下炕吸,當(dāng)瀏覽器關(guān)閉后,Cookies 自動(dòng)銷毀勉痴『漳#可以設(shè)置 Cookies 的 optons 參數(shù)(maxAge
或者expires
,兩者選其一)設(shè)置 Cookies 有效期蒸矛。
-
Cookies 如何設(shè)置中文瀑罗?
默認(rèn)情況下,Egg.js 中的 Cookies 無(wú)法設(shè)置中文雏掠。但是斩祭,如果對(duì) Cookies 進(jìn)行加密操作,則可以設(shè)置中文 Cookies 了乡话。還有一種方式摧玫,也可以通過(guò)將 Buffer 轉(zhuǎn)換為 base64 進(jìn)行設(shè)置中文 Cookies。
-
Cookies 如何設(shè)置對(duì)象绑青?
對(duì)對(duì)象進(jìn)行序列化和反序列化操作即可設(shè)置對(duì)象:JSON.stringify()
JSON.parse()
如何清除 Cookies诬像?
將 Cookies 設(shè)置為空:this.ctx.cookies.set('name',null)
,或者設(shè)置maxAge
過(guò)期時(shí)間為 0。
Session
Session 是另一種記錄客戶端狀態(tài)的機(jī)制闸婴,不同的是 Cookies 保存在客戶端瀏覽器中坏挠,而 Session 保存在服務(wù)器上。
Session 的工作流程
當(dāng)瀏覽器訪問(wèn)服務(wù)器并發(fā)送第一次請(qǐng)求時(shí)邪乍,服務(wù)器端會(huì)創(chuàng)建一個(gè) session 對(duì)象降狠,生成一個(gè)類似于 key,value 的鍵值對(duì)庇楞,然后將 key(cookie) 返回到瀏覽器(客戶)端榜配,瀏覽器下次再訪問(wèn)時(shí),攜帶 key(cookie)吕晌,找到對(duì)應(yīng)的 session(value)芥牌。
示例代碼
設(shè)置 Session :
'use strict';
const Controller = require('egg').Controller;
class HomeController extends Controller {
async index() {
// ?????? 設(shè)置 session
this.ctx.session.username = 'Andy';
// 顯示表單頁(yè)面,加載并渲染 HTML 模版文件
// this.ctx.csrf 用戶訪問(wèn)頁(yè)面時(shí)生成的密鑰
await this.ctx.render('home');
}
}
module.exports = HomeController;
獲取 Session:
'use strict';
const Controller = require('egg').Controller;
class NewsController extends Controller {
// 獲取數(shù)據(jù)顯示到新聞頁(yè)面
async index() {
// ?????? 獲取 session 值
const username = this.ctx.session.username;
console.log(username);
// 調(diào)用 Service 層方法
const listInfo = await this.service.news.getNewsList();
// 渲染模版引擎
await this.ctx.render('news', { list: listInfo });
}
}
module.exports = NewsController;
設(shè)置 Session 的有效期
方法一:
'use strict';
const Controller = require('egg').Controller;
class HomeController extends Controller {
async index() {
// 設(shè)置 session
this.ctx.session.username = 'Andy';
// ?????? 設(shè)置 Session 的過(guò)期時(shí)間(基于 Cookies)聂使,默認(rèn)過(guò)期時(shí)間 24H.
this.ctx.session.maxAge = 2000;
// 顯示表單頁(yè)面壁拉,加載并渲染 HTML 模版文件
// this.ctx.csrf 用戶訪問(wèn)頁(yè)面時(shí)生成的密鑰
await this.ctx.render('home');
}
}
module.exports = HomeController;
方法二(全局配置)
推薦在 config.default.js 文件中設(shè)置 Session。
因?yàn)?Session 是基于 Cookies 的柏靶,所以 Session 的配置和 Cookies 基本是一樣的弃理,可以使用 Cookies 里面的配置:
// 配置 Session
config.session = {
key: 'SESSION_ID', // 設(shè)置 Session cookies 里面的 key
maxAge: 24 * 3600 * 1000, // 1 天
httpOnly: true,
encrypt: true,
renew: true, // 每次刷新頁(yè)面,Session 都會(huì)被延期屎蜓。
};