koa-send源码解析

介绍

Simple session middleware for Koa. Defaults to cookie-based sessions and supports external stores.

意为,Koa 简单的中间件。默认基于 cookie 的会话存储,支持终端存储。

源码 koa-session 6.2.0

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
const debug = require("debug")("koa-session");
const ContextSession = require("./lib/context");
const util = require("./lib/util");
const assert = require("assert");
const uuid = require("uuid/v4");
const is = require("is-type-of");

const CONTEXT_SESSION = Symbol("context#contextSession");
const _CONTEXT_SESSION = Symbol("context#_contextSession");

module.exports = function (opts, app) {
// 修正参数位置,类似session(app[, opts])
if (opts && typeof opts.use === "function") {
[app, opts] = [opts, app];
}
// app是必传参数
if (!app || typeof app.use !== "function") {
throw new TypeError("app instance required: `session(opts, app)`");
}

// 格式化参数
opts = formatOpts(opts);
// 扩展context
extendContext(app.context, opts);

return async function session(ctx, next) {
const sess = ctx[CONTEXT_SESSION];
if (sess.store) await sess.initFromExternal();
try {
await next();
} catch (err) {
throw err;
} finally {
if (opts.autoCommit) {
await sess.commit();
}
}
};
};

function formatOpts(opts) {
// 初始化参数对象
opts = opts || {};
// 设置会话的cookie名,默认koa.sess
opts.key = opts.key || "koa.sess";

// 兼容maxage
if (!("maxAge" in opts)) opts.maxAge = opts.maxage;

// defaults
if (opts.overwrite == null) opts.overwrite = true;
if (opts.httpOnly == null) opts.httpOnly = true;
// 删除 null sameSite配置
if (opts.sameSite == null) delete opts.sameSite;
if (opts.signed == null) opts.signed = true;
if (opts.autoCommit == null) opts.autoCommit = true;

debug("session options %j", opts);

// 设置编码/解码函数
if (typeof opts.encode !== "function") {
opts.encode = util.encode;
}
if (typeof opts.decode !== "function") {
opts.decode = util.decode;
}

// 下边都是assert判断函数类型
const store = opts.store;
if (store) {
assert(is.function(store.get), "store.get must be function");
assert(is.function(store.set), "store.set must be function");
assert(is.function(store.destroy), "store.destroy must be function");
}

const externalKey = opts.externalKey;
if (externalKey) {
assert(is.function(externalKey.get), "externalKey.get must be function");
assert(is.function(externalKey.set), "externalKey.set must be function");
}

const ContextStore = opts.ContextStore;
if (ContextStore) {
assert(is.class(ContextStore), "ContextStore must be a class");
assert(
is.function(ContextStore.prototype.get),
"ContextStore.prototype.get must be function"
);
assert(
is.function(ContextStore.prototype.set),
"ContextStore.prototype.set must be function"
);
assert(
is.function(ContextStore.prototype.destroy),
"ContextStore.prototype.destroy must be function"
);
}

// 生成一个唯一id
if (!opts.genid) {
if (opts.prefix) opts.genid = () => `${opts.prefix}${uuid()}`;
else opts.genid = uuid;
}

return opts;
}

// 扩展context原型,增加session属性
function extendContext(context, opts) {
// 如果存在返回
if (context.hasOwnProperty(CONTEXT_SESSION)) {
return;
}
Object.defineProperties(context, {
// 向外暴露
[CONTEXT_SESSION]: {
get() {
if (this[_CONTEXT_SESSION]) return this[_CONTEXT_SESSION];
this[_CONTEXT_SESSION] = new ContextSession(this, opts);
return this[_CONTEXT_SESSION];
},
},
// 暴露session方法,用于获取和设置session
session: {
get() {
return this[CONTEXT_SESSION].get();
},
set(val) {
this[CONTEXT_SESSION].set(val);
},
configurable: true,
},
// 获取session上的opts参数,也就是传入时的参数
sessionOptions: {
get() {
return this[CONTEXT_SESSION].opts;
},
},
});
}

参考链接

打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

给阿姨来一杯卡普基诺~

支付宝
微信