上节我们实现了注册功能,但仍有个严重的问题,不论是成功还是失败,我们都没有给页面任何反馈。这也是缺失了我们页面设计里重要的一环——通知。
通知应该怎么实现呢?
这涉及到一个服务端开发一个重要的知识点——session。而session又严重依赖于cookie。
HTTP协议是无状态的,无状态的意思是,同一个页面,当你刷新之后浏览器就不记得你是谁了。这个情况在HTML刚出来的时候是可以的,因为当时页面偏展示,轻交互。但当网站有了用户的概念后,这就不行了,必须有个解决方案,于是cookie就应运而生。
一个同源的API或资源调用,都会携带自身的cookie表明自己的身份。同样的,浏览器允许服务器在响应时设置或删除cookie字段。
session的使用就是利用这点:
- 浏览器第1次请求 -> 服务器,以某种算法生成一个session-id(比如随机字符串Xep5LG8rwNX5f1euUn_ak),将用户信息存储起来(可以在本地内存,也可以在数据库),以cookie中某个字段(比如就叫session-id)的形式返回给前端。
- 浏览器第2次请求 -> 服务器,服务器从cookie中查找到session-id,再相应查找用户信息,找到了,就将这次请求认为与上次是同一个会话,如果没有找到,则认为是新用户,重复第1条。
我们用个例子体验下。
样例
修改src/app.controller.ts
import { Context, Controller, Get } from "oak_nest";
@Controller("")
export class AppController {
@Get("/test")
async test(context: Context) {
const usersMap = new Map<string, Record<string, string | number>>();
usersMap.set("1", {
name: "test",
age: 1,
});
usersMap.set("2", {
name: "test2",
age: 2,
});
const sessionKey = "session-id";
const sessionId = await context.cookies.get(sessionKey);
if (sessionId) {
const user = usersMap.get(sessionId);
if (user) {
context.response.body = user;
return;
}
}
await context.cookies.set(sessionKey, "1");
context.response.body = "no session";
}
}
打开浏览器,先打开F12,再访问http://localhost:8000/test,页面不出意外返回的是个字符串:
在网络里观察,看响应头里是不是多了个session-id?
Cookie的tab页里看的更清晰:
在应用-存储-Cookie里也能找到:
刷新页面,看是不是变化了?
注意看这次请求头里,携带了这个Cookie:
下来我们再来个骚操作,在刚才应用-存储-Cookie里找到这条cookie,把值修改为2
再刷新页面:
所以,你在任何网站的cookie都代表了你的个人信息,如果它被别人盗取了,就相应于盗用了你的身份,就会冒充你干出非法的勾当来。
现在你对session了解了吗?
作业
上面的代码可以删了。
思考下,应该怎么写中间件,实现通知功能?