多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[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)