Skip to content

实战:李瓶儿博客开发

TIM截图20200123173701

http 请求概述

从输入 url 到页面显示中间发生了什么

  • DNS 解析,建立 TCP 连接,发送 http 请求

  • server 接收到 http 请求,处理,并返回

  • 客户端接收到返回数据,处理数据(如渲染页面,执行 js)

nodejs 处理 http 请求

  • get 请求和 querystring
  • post 请求和 postdata
  • 路由

TIM截图20200123223412

MySQL

  • mysql 介紹、安裝和使用
  • nodejs 连接 mysql
  • API 连接 mysql

为什么使用 mysql 而不是 mogondb

  • mysql 是企业内最常见的存储工具,一般都有专人运维
  • mysql 也是社区内最常用的存储工具,有问题可以随时可查
  • 另:mysql 本身是一个复杂的数据库软件,本课只讲基本使用

mysql 介绍

  • web server 中最流行的关系型数据库
  • 官网可免费下载,用于学习
  • 轻量级,易学易用

mysql workbench 可视化数据库

mysql 命令

show databases 显示所有的数据库表

mysql 安装步骤

https://zhuanlan.zhihu.com/p/37152572

操作数据库

操作表

增、删、改、查

使用 sql 语句(入门简单,一学就会)

sql
insert into users(username, `password`, realname) values('lisi', '123', '李四')

查 users 表所有信息

sql
select * from users;

查 users 表中其中 id 和 username 的信息

sql
select id, username from users;

查符合条件的项 where

sql
select * from users where username='zhangsan'

查符合条件的项多个条件 andor

sql
select * from users where username='zhangsan' and realname='111'

模糊查询 like

sql
select * from users where username like '%zhang%'

查 排序 order by id 默认正序,如果倒序 在 id 后加 desc order by id desc

sql
select * from users where username like '%zhang%' order by id desc;

ps:一般不用 * ,耗性能

更新 id 为 3 的 realname 为张三

sql
update users set realname='张三' where id='3'

sql
delete from users where realname='李四'

但一般来说不用 delete,二是在 users 表中加一个状态,通过状态来判断他是否被删除。这种技术又称软删除

PS:如果你的更新和删除出现 error:1175 处于安全模式,先使用以下代码解除安全模式

sql
SET SQL_SAFE_UPDATES=0;

登录

  • cookie 和 session
  • session 写入 redis
  • 开发登录功能,和前端联调(用到 nginx 反向代理)
  • 什么是 cookie
  • javascript 操作 cookie,浏览器中查找 cookie
  • server 端操作 cookie,实现登录验证

什么是 cookie?

  • 存储在浏览器中的一段字符串(最大 4KB)
  • 跨域不共享
  • 格式如 k1=v1;k2=v2;k3=v3;因此可以存储结构化数据
  • 特点一:每次发送 http 请求,会将请求域的 cookie 一起发送给 server
  • 特点二:server 可以修改 cookie 并返回给浏览器
  • 特点三:浏览器中也可以通过 javascript 修改 cookie (有限制)
javascript
res.setHeader(
    'Set-Cookie',
    `username=${
        data.username
    }; path=/; httpOnly; expires=${getCookieExpires()}`,
);

path:根域名下 cookie 共享

httpOnly:只能服务器修改,浏览器不能修改

expires:设置过期时间

session

cookie 的缺点,会暴露 username,很危险,不安全

cookie 可以存储 userid,server 端对应 username

cookie 放不重要的数据,放 userid(一个标识)对应 server 端的 username

就能做到数据的保密

解决方案:session,即 server 端存储用户信息

session 造成的问题

目前 session 直接是 js 变量,放在 nodejs 进程内存中

第一,进程内存有限,访问量过大,内存暴增怎么办?

第二,正式线上运行是多线程,进程之间内存无法共享

TIM截图20200206165902

系统内存之间有多个线程,线程之间不共享内存

解决方案 redis

  • web server 最常用的缓存数据库,数据库放在内存中
  • 相比于 mysql,访问速度快(内存和硬盘不是一个数量级的)
  • 但是成本更高,可存储的数量更小(内存硬伤)

如果解决

  • 将 web server 和 redis 拆分为两个独立的服务
  • 双方都是独立的,都是可扩展的(例如都扩展成集群)
  • (包括 mysql,也是一个单独的服务,可扩展)

TIM截图20200206170732

登录等数据放在 redis,数据有关的放在 mysql,都是相对独立的服务

数据分离,可以扩展

为什么 session 适合用 redis?

  • session 访问频繁,对性能要求高(redis 内存数据库,速度快)
  • session 可不考虑断电丢失数据的问题(内存的硬伤)
  • session 数据量不会太大(内存小,相比 mysql 中的数据小的多)

安装 redis

https://www.runoob.com/redis/redis-install.html

启动 redis

redis-server ,要一直连接状态(服务在线)

在命令行中敲 redis-cli,进入 redis 操作中

常见的 redis 操作

命令解释例子
set key value设置 keyset myname hanbo
get key得到 keyget myname
del key删除 keydel myname
keys *显示所有的 keykeys *

为何要用 redis?不用 redis 会出现什么问题?

redis 适合什么场景?mysql 适合什么场景?

要保存状态机,如果你要一直保存登录状态,就要从内存中读取数据,而不是去请求数据库

请求数据库需要花时间,

redis 适合登录 状态这种情况

与前端联调

  • 登录功能依赖 cookie ,必须用浏览器来联调
  • cookie 跨域不共享,前端和 server 端必须同域
  • 需要用到 nginx 做代理,让前后端同域

使用 nginx 反向代理请求

nginx

  • 高性能的 web 服务器,开源免费
  • 一般用于做静态服务、负载均衡
  • 反向代理

TIM截图20200207152320

日志

  • 系统没有日志,就等于人没有眼睛——抓瞎
  • 第一,访问日志 access log (server 端最重要的日志)
  • 第二,自定义日志(包括自定义事件、错误记录等)

目录

  • nodejs 文件操作,nodejs stream
  • 日志功能开发和使用
  • 日志文件拆分,日志内容分析

nodejs 文件操作

  • 日志要存放到文件中
  • 为何不存储到 mysql 中?
  • 为何不存储到 redis 中?
javascript
const fs = require('fs');
const path = require('path');

const fileName = path.resolve(__dirname, 'data.txt');

// 读取文件内容
// fs.readFile(fileName, (err, data) => {
//   if (err) {
//     console.log(err)
//     return;
//   }
//   console.log(data.toString())
// })

// 写入文件内容
// const content = '这是新写入的内容\n';
// const opt = {
//   flag: 'a'   // 追加写入。覆盖用'w'
// }
// fs.writeFile(fileName, content, opt, (err) => {
//   if (err) {
//     console.log(err)
//   }
// })

// 判断文件是否存在
fs.exists(fileName, (exist) => {
    console.log('exist', exist);
});

IO 操作的性能瓶颈

  • IO 包括”网络 IO”和“文件 IO”
  • 相比于 CPU 计算和内存读写, IO 的突出特点就是:慢!
  • 如何在有限的硬件资源下提高 IO 的操作效率?

TIM截图20200214145700

stream 流,一点点流过去,一点点读取

日志分析

  • 如针对 access.log 日志,分析 chrome 的占比

  • 日志是按行存储的,一行就是一条日志

  • 使用 nodejs 的 readline(基于 stream ,效率高)

readline 可以分析 数据,做数据统计用

安全

  • sql 注入:窃取数据库内容
  • XSS 攻击:窃取前端的 cookie 内容
  • 密码加密:保障用户信息安全(重要!)加盐

sql 注入

  • 最原始、最简单的攻击,从有了 web2.0 就有了 sql 注入攻击
  • 攻击方式:输入一个 sql 片段,最终拼接成一段攻击代码
  • 预防措施:使用 mysql 的 escape 函数处理输入内容即可

XSS 攻击

  • 前端最熟悉的攻击方式, 方式 server 端更应该掌握
  • 攻击方式:在页面展示内容中掺杂 js 代码,以获得网页信息
  • 预防措施: 转换生成 js 的特殊字符

密码加密

  • 万一数据库被用户攻破,最不应该泄露的就是用户信息
  • 攻击方式:获取用户名和密码,再去尝试登录其他系统
  • 预防措施:将密码加密,即便拿到密码也不知道明文

总结:

功能模块

  • 处理 http 接口
  • 连接数据库
  • 实现登录
  • 安全
  • 日志
  • 上线

核心知识

  • http,nodejs 处理 http、处理路由、mysql
  • cookie,session,redis,nginx 做反向代理
  • sql 注入,xss 攻击,加密
  • 日志,stream,contrab,readline
  • 线上环境的知识

使用 express 来开发 web server

express.json() 解析 post 请求

中间件机制

  • 有很多 app.use
  • 代码中的 next 参数是什么?
  • 带着这些疑问,先看一段代码演示

express 总结

中间件原理介绍

分析
  • app.use 用来注册中间件,先收集起
  • 遇到 http 请求,根据 path 和 method 判断触发哪些
  • 实现 next 机制,即上一个通过 next 触发下一个

使用 Koa2

  • express 中间件是异步回调,koa2 原生支持 async/await
  • 新开发框架和系统,都开始基于 koa2,例如 egg.js
  • express 虽然未过时,但是 koa2 肯定是未来趋势

目录

  • async/await 语法介绍,安装和使用 koa2
  • 开发接口,链接数据库,实现登录,日志记录
  • 分析 koa2 中间件原理

async await 要点:

  1. await 后面可以追加 promise 对象,获取 resolve 的值
  2. await 必须包裹在 async 函数里面
  3. async 函数执行返回的也是一个 promise 对象
  4. try-catch 截获 promise 中 reject 的值

中间件机制

  • 有很多 app.use
  • 代码中的 next 参数是什么?

app.use 和 express 一致,使用中间件

洋葱模型

实现登录

  • 和 express 类似
  • 基于 koa-generic-session 和 koa-redis

线上环境

  • 服务器稳定性
  • 重温利用服务器硬件资源,以便提高性能
  • 线上日志记录

PM2

  • 进程守护,系统奔溃自动重启
  • 启动多进程,充分利用 CPU 和内存
  • 自带日志记录功能

PM2 介绍

  • 下载安装

    • npm install pm2 -g
    • pm2 --version
  • 基本使用

  • 常用命令

    pm2 start [app.js] 启动

    pm2 restart [app.js] 重启

    pm2 stop [app.js] 停止

    pm2 list 查看启动列表

    pm2 info <AppName>/<id> 查看基本信息

    pm2 log <AppName>/<id> 查看日志打印

    pm2 monit <AppName>/<id> 监控这个进程的 CPU 和内存信息

PM2 进程守护

课程总结

课程总结