目标
需求
技术方案
- 数据存储
- mysql存储博客数据
- redis存储用户信息
- mysql存储博客数据
- 接口设计
知识点
- 开发接口
- nodejs处理http请求
- get请求
就可以在localhost看到hello world字样const http = require('http') const querystring = require('querystring') const server = http.createServer((req, res) => { console.log('method: ', req.method) // GET const url = req.url console.log('url: ',url) req.query = querystring.parse(url.split('?')[1]) console.log('query: ', req.query) res.end( JSON.stringify(req.query) ) }) server.listen(8000) console.log('OK') - post请求
需要用到postman调试
const http = require('http'); const querystring = require('querystring'); const sever = http.createServer((req, res) => { if (method === 'POST') { // req 数据格式 console.log('req Content-type: ', req.headers['Content-type']) // 接受数据 let postData = ''; req.on('data', chunk => { postData += chunk.toString() }) req.on('end', () => { resData.postData = postData res.end( JSON.stringify(resData) ) }) } }); sever.listen(8000); console.log('ok')- get&post综合演示
const http = require('http'); const querystring = require('querystring'); const sever = http.createServer((req, res) => { const method = req.method; const url = req.url; const path = url.split('?')[0]; const query = querystring.parse(url.split('?')[1]); // 设置返回格式为 JSON res.setHeader('Content-type', 'application/json') // 返回的数据 const resData = { method, url, path, query, // url携带参数 } // 返回 if (method === 'GET') { res.end( JSON.stringify(resData) ) } if (method === 'POST') { let postData = ''; req.on('data', chunk => { postData += chunk.toString() }) req.on('end', () => { resData.postData = postData res.end( JSON.stringify(resData) ) }) } }); sever.listen(8000); console.log('ok') - 搭建开发环境
使用nodemon监测文件变化,自动重启node;
使用cross-env 设置环境变量- 路由
- 开发路由
- 路由
- get请求
- nodejs处理http请求
- 数据存储
- 操作数据库
使用Mysql Workbench- 建库
- 建表
- 表操作
- 增删改查
- nodejs操作mysql
const mysql = require('mysql') // 创建链接对象 const con = mysql.createConnection({ host: 'localhost', user: 'root', password: '123456', port: '3306', database: 'myblog' }) // 开始连接 con.connect() // 执行 sql 语句 const sql = `select * from users;` con.query(sql, (err, result) => { if (err) { console.error(err) return } console.log(result) }) // 关闭连接 con.end()
- 操作数据库
- 登录
核心:登录校验 & 登录信息存储- 登录校验
- cookie
- 存储在浏览器的一段字符串(最大5kb)
- 跨域不共享
- 格式如:k1=v1;k2=v2;因此可以存储结构化数据
- 每次发送http请求,会将请求域的cookie一起发送给server
- server可以修改cookie并返回给浏览器
- nodejs操作cookie
- 查看cookie
req.headers.cookie - 修改cookie
其中path为cookie起作用的路径,httpOnly设置是防止通过js脚本读取到cookie信息// 操作cookie res.setHeader('Set-Cookie', `userid=${userId}; path=/; httpOnly; expires=${getCookieExpires()}`) - 实现登录验证
登录登录验证(测试)// 登录 if (method === 'POST' && req.path === '/api/user/login') { // const { username, password } = req.query // 从数据库中查询对应数据(login函数) const result = login(username, password) return result.then(data => { if (data.username) { // 操作cookie res.setHeader('Set-Cookie', `userid=${userId}; path=/; httpOnly; expires=${getCookieExpires()}`) return new SuccessModel() } return new ErrorModel('登录失败') }) }(cookie补充)给cookie做限制// 登录验证测试 if (method === 'GET' && req.path === '/api/user/login-test') { // 如果cookie中存在username 则登录成功 if (req.cookie.username) { return Promise.resolve( new SuccessModel({ usrename: req.cookie.username }) ) } return Promise.resolve( new ErrorModel('尚未登录') ) }
1.对JS修改cookie做限制httpOnly属性
2.对cookie设置过期时间expires属性
-
session
- 为什么使用session:
- 为了解决cookie会暴露username很危险,所以将cookie存储userid,server端对应username,即用cookie存储userId,server端存储用户信息
- session运行在服务器端,当客户端第一次访问服务器时,可以将客户的登陆信息保存。
- 当客户访问其他界面时,可以判断客户的登陆状态,做出提示。
- 可以保存一些客户的常用信息,当客户端再次获取常用信息时,不必再从数据库中进行查询。
- session可以与redis或数据库等结合做持久化操作,当服务器挂掉时也不会导致某些客户信息(购物车)消失。
- session的工作流程:
- 当浏览器访问服务器并发送第一次请求时,服务器端会创建一个session对象,生成一个类似于key,value的键值对,
- 然后将key(cookie)返回到浏览器(客户)端,浏览器下次再访问时,携带key(cookie),找到对应的session(value)。
- 用户的信息都保存在session中。
- 示例
// session 数据 const SESSION_DATA = {} // 解析session(未使用redis) let needSetCookie = false // 设置是否需要设置cookie的制位符 let userId = req.cookie.userid // 获取当前userid if (userId) { if (!SESSION_DATA[userId]) { // 有cookie,设置对应session SESSION_DATA[userId] = {} } } else { needSetCookie = true userId = `${Date.now()}_${Math.random()}` SESSION_DATA[userId] = {} } req.session = SESSION_DATA[userId]
- 为什么使用session:
-
redis
- 引入redis的原因:
- 目前session放在nodejs进程内存中,进程内存有限,访问量过大,内存暴增
- 正式上线运行是多进程,进程之间内存无法共享
-
nodejs中使用redis
安装redis
npm install redisconst redis = require('redis') // 创建客户端 const redisClient = redis.createClient(6379, '127.0.0.1') redisClient.on('error', err => { console.log(err) }) // 测试 redisClient.set('myname', 'zhangsan2', redis.print) redisClient.get('myname', (err, val) => { if(err) { console.log(err) return } console.log('val ', val) redisClient.quit() })
- cookie
- 登录信息存储
- 登录校验
- 日志
- 安全