[TOC]
>[success] # cookie用于登录验证
接下来了解一下通过 **nodejs** 操作 **cookie** :
* **查看 cookie**
* **修改 cookie**
* **实现登陆验证**
>[success] ## 查看 cookie
我们在 **app.js** 中来 **解析 cookie** ,首先从 **请求头中获取 cookie** ,**cookie 格式: k1=v1;k2=v2;k3=v3** ,这种格式要取出这里某一个信息比较麻烦,所以 **需要通过 split 来分割一下,然后组装成 js对象的数据**,存入到 **res.cookie** 中 ,代码如下:
**blog-1/app.js**
~~~
const querystring = require('querystring')
// 引入处理路由文件
const handleBlogRouter = require('./src/router/blog')
const handleUserRouter = require('./src/router/user')
// 用于处理 post data
const getPostData = (req) => {
const promise = new Promise((resolve, reject) => {
if(req.method !== 'POST'){ // 不等于 post 请求
resolve({})
return
}
if(req.headers['content-type'] !== 'application/json'){ // 传入的数据格式不是 application/json ,可能是form-data的参数
resolve({})
return
}
// 1. POST通过数据流方式接收数据
let postData = ''
// 2. 给req注册data事件,当有数据提交过来就会触发,事件的作用是接收数据,接收大量数据的时候,是分块接收的
req.on('data', chunk => {
postData += chunk.toString()
})
// 3. 给req注册end事件,当数据全部接收完毕,会触发
req.on('end', () => {
if(!postData){ // 无数据返回空对象
resolve({})
return
}
resolve(
JSON.parse(postData)
)
})
})
return promise
}
const serverHandle = (req, res) => {
// 设置返回格式 JSON
res.setHeader('Content-type', 'application/json')
// 获取 path
const url = req.url
req.path = url.split('?')[0]
// 解析query 参数
req.query = querystring.parse(url.split('?')[1])
// 解析 cookie
req.cookie = {}
const cookieStr = req.headers.cookie || '' // 格式: k1=v1;k2=v2;k3=v3
cookieStr.split(';').forEach(item => {
if(!item){
return
}
const arr = item.split('=')
const key = arr[0].trim()
const value = arr[1].trim()
req.cookie[key] = value
});
// 处理 post data 参数
getPostData(req).then(postData => {
req.body = postData
// 处理 blog 路由
const blogResult = handleBlogRouter(req, res)
if(blogResult){
blogResult.then(blogData => {
res.end(
JSON.stringify(blogData)
)
})
return // 这里需要return,不然返回数据后还会往下走
}
// 处理 user 路由
const userResult = handleUserRouter(req, res)
if(userResult){
userResult.then(userData => {
res.end(
JSON.stringify(userData)
)
})
return
}
// 未命中路由,返回 404
res.writeHead(404, {"Content-type": "text/plain"}) // 把响应头状态码设置为404,然后Content-type: text/plain是纯文本,为了覆盖上面的json类型
// 返回内容
res.write('404 Not Found\n')
res.end()
})
}
module.exports = serverHandle
~~~
然后我们可以打印一下 **res.cookie** 是什么,然后输入 **http://localhost:8000/api/blog/list** 访问我们写好的接口,此时控制台如果没有 **cookie** ,我们可以通过之前学的 `document.cookie` 手动去控制台添加一个 **cookie** ,如图:
![](https://img.kancloud.cn/0e/34/0e3424d6f836e64f93e54cf77865132f_290x76.png)
我们在浏览器通过手动添加的方式添加了一个 **name=xiaoming;** 的 **cookie** ,此时我们的 **nodejs** 控制台打印结果就是
~~~
{
name: 'xiaoming'
}
~~~
这时候就可以看到我们添加的 **cookie** 了。
>[success] ## 实现登陆验证
首先我们模拟写一个 **简单的登陆验证** ,然后熟悉了后,再写一个真正的登陆验证
>[success] ### 登陆验证 demo
接下来实现一个简单的 **登陆验证 demo** ,**前端把 cookie 传给后端,后端查看 cookie 中是否有 username ,如果有 username 就证明已登陆,如果没有就是未登录** ,这样就是一个最简单的登陆验证,在 **blog-1/src/router/user.js** 中新增一个测试接口 **/api/user/login-test** 来测试一下,代码如下:
**blog-1/src/router/user.js**
~~~
// 从 controller 中获取数据
const { login } = require('../controller/user')
// 引入数据模型
const { SuccessModel, ErrorModel } = require('../model/resModel')
const handleUserRouter = (req, res) => {
const method = req.method // GET POST
// 登陆
if(method === 'POST' && req.path === '/api/user/login'){
const { username, password } = req.body
const result = login(username, password)
return result.then(data => {
if(data.username){ // 登陆成功
return new SuccessModel()
} else {
return new ErrorModel('登陆失败')
}
})
}
// 登陆验证的测试
if(method === 'GET' && req.path === '/api/user/login-test'){
if(req.cookie.username){ // 如果有用户名,登陆成功,如果没有尚未登录
return Promise.resolve(new SuccessModel())
}
return Promise.resolve(new ErrorModel('尚未登录'))
}
}
module.exports = handleUserRouter
~~~
这里的 **/api/user/login-test** 接口就是我们测试用的的 **登陆验证接口**,因为外层需要返回一个 **Promise** 对象,这里如果不想封装嫌麻烦的话可以直接使用 **Promise.resolve** ,然后我们接下来在浏览器访问 `http://localhost:8000/api/user/login-test` ,页面显示如下:
![](https://img.kancloud.cn/62/e3/62e31927ea1f7af96007e1c51f7b490e_320x73.png)
这时候是没有 **cookie** 的,所以我们先手动添加一个有 **username** 的 **cookie**
~~~
document.cookie = 'username=xiaoming;'
~~~
**添加成功** 后再次 **刷新浏览器**,就会看到 **请求接口时候通过请求头** 传给后端了
![](https://img.kancloud.cn/b2/d1/b2d1f9b461692c9922928d7ac4e6c19b_1133x787.png)
然后页面就显示显示 **errno:0** 代表成功了
![](https://img.kancloud.cn/f9/38/f938abd5b91240ac3f1cd09b2f67b8a1_183x46.png)
>[success] ### 实战登陆验证 与 修改 cookie
刚才的上面的 **登陆验证 demo** 中使用到的 **cookie** 是我们手动在浏览器上添加的,**实际项目场景中,应该是后端人员进行添加的** ,接下来就来实现在 **nodejs** 中进行添加 **cookie** ,首先在 **blog-1/src/router/user.js** 中进行修改,通过 `res.setHeader('Set-Cookie', `username=${data.username}; path=/`)` 来添加 **cookie** ,这里的 **path=/** 意思是 **cookie 在根目录下都有效 ,如果不写 path=/ ,path 默认是 path=/api/user 这样就会导致只有 user 下的接口好用,其他接口都不好用,** 代码如下:
**blog-1/src/router/user.js**
~~~
// 从 controller 中获取数据
const { login } = require('../controller/user')
// 引入数据模型
const { SuccessModel, ErrorModel } = require('../model/resModel')
const handleUserRouter = (req, res) => {
const method = req.method // GET POST
// GET 方式登陆(为了测试在浏览器看更直观,所以用的get请求,正常项目开发中使用post请求)
if(method === 'GET' && req.path === '/api/user/login'){
const { username, password } = req.query
const result = login(username, password)
return result.then(data => {
if(data.username){ // 登陆成功
// 添加 cookie,path=/适用于根目录下所有接口,如果不写path=/,默认是path=/api/user
res.setHeader('Set-Cookie', `username=${data.username}; path=/`)
return new SuccessModel()
} else {
return new ErrorModel('登陆失败')
}
})
}
// // POST 登陆(正常用POST方式登陆)
// if(method === 'POST' && req.path === '/api/user/login'){
// const { username, password } = req.body
// const result = login(username, password)
// return result.then(data => {
// if(data.username){ // 登陆成功
// // 添加 cookie,path=/适用于根目录下所有接口,如果不写path=/,默认是path=/api/user
// res.setHeader('Set-Cookie', `username=${data.username}; path=/`)
// return new SuccessModel()
// } else {
// return new ErrorModel('登陆失败')
// }
// })
// }
// 登陆验证的测试
// if(method === 'GET' && req.path === '/api/user/login-test'){
// if(req.cookie.username){ // 如果有用户名,登陆成功,如果没有尚未登录
// return Promise.resolve(new SuccessModel())
// }
// return Promise.resolve(new ErrorModel('尚未登录'))
// }
}
module.exports = handleUserRouter
~~~
代码中把刚才的 **登陆验证的测试** 代码注释上了,因为这个只是暂时用来做测试的,正常情况下用不到这个,然后把 **/api/user/login** 接口复制了一份,并且改成了 **GET 请求** ,因为 **POST请求** 时,需要用 **postman** 来请求,在 **postman** 上无法查看 **后台添加 Set-Cookie** 的信息,用 **GET 请求** 在 **浏览器上查看比较更直观** ,但是在真正项目中登陆还是要用 **POST请求** ,这里做演示就先使用 **GET请求** 接下来我们访问 `http://localhost:8000/api/user/login` 页面,会直接提示 **登陆失败**
![](https://img.kancloud.cn/b2/38/b23851d4005ae1888acf387af844c428_330x57.png)
此时我们在通过 **GET请求的方式在 URL** 后面拼接上 **username 跟 password** `http://localhost:8000/api/user/login?username=lisi&password=123` ,页面就会显示登陆成功的样式了,并且还可以看到 **响应头** 中显示了后端通过 **Set-Cookie** 添加了 **cookie**
![](https://img.kancloud.cn/93/6f/936f9095044d118e5239ab7edf96e18d_1419x885.png)
这个时候可以 **尝试访问其他接口查看 cookie 是否在请求头中携带** 。
>[success] ## 总结
1. **查看 cookie:在 req.headers.cookie 中就可以查看传过来的 cookie**
2. **修改 cookie:通过 res.setHeader 来添加 Set-Cookie 即可,只不过需要设置一些 cookie 的参数**
3. **验证登陆:登陆时去数据库查询是否存在该用户,如果存在就把该用户的 username 通过 Set-Cookie 存入到 cookie 中**
4. 如果想手动删除 **cookie**,可以去浏览器的 **application** 手动把 **cookie 删掉**
![](https://img.kancloud.cn/9b/e5/9be5f7c5b049c672fc2323fceaa4831e_1899x409.png)
- NodeJS基础
- 什么是NodeJS
- npm
- Node.js+Express+Koa2+开发Web Server博客
- 下载和安装node
- nodejs和js的区别
- commonjs-演示
- nodejs如何debugger
- server端与前端的区别
- 项目需求分析
- 开发接口(不使用任何框架)
- http-概述
- 处理get请求
- 处理post请求
- 处理http请求的综合示例
- 搭建开发环境
- 初始化并且开发路由
- 开发博客项目之数据存储
- MySql介绍
- 数据库操作(创建和增、删、查)
- Nodejs 操作 Mysql
- Nodejs 链接 mysql 做成工具
- API 对接 MySQL
- 开发博客项目之登陆
- cookie-介绍
- cookie用于登录验证
- cookie做限制