系统架构设计的四层抽象:html
整体结构:前端
1、session不足:node
解决:将session存储在Redis中mysql
2、为什么session适合用Redis存储nginx
3、开启redis服务:web
打开一个 cmd 窗口 使用 cd 命令切换目录到redis目录下 运行redis
redis-server.exe redis.windows.conf
复制代码
如何配置反向代理:sql
nginx.conf
配置文件:数据库
location / {
# 若是是根目录(即 http://localhost:8080)则代理到 8001 端口
proxy_pass http://localhost:8001;
}
location /api/ {
# 若是是访问接口,则代理到 8000 端口
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
}
复制代码
http://localhost:8080/index.html
便可ps:express
start nginx
http-server -p8001
npm run dev
Nginx命令
构建流程
npm install -g express -generator
全局安装express命令安装工具express 项目名
npm install
安装组件npm start
启动项目(服务器)npm i nodemon cross-env
写本身的业务逻辑:
blog.js
)引入app.js
文件中,并使用app.use
注册咱们的路由相对于原生nodejs:
req.query
获取get传过来的参数,经过req.body
获取 post传过来的参数res.json
直接返回json数据给客户端express-session
、connect-redis
、登录中间件morgan
来记录日志,根据配置决定将日志输出到控制台仍是文件中构建流程
npm install koa-generator -g
全局安装express命令安装工具Koa2 项目名
npm install
安装组件npm i cross-env
npm run dev
启动项目(服务器)相对于express和原生nodejs:
ctx.query
获取get传过来的参数,经过ctx.request.body
获取 post传过来的参数ctx.body
直接返回json数据给客户端async/await
来实现中间件await next()
来执行下一个中间件express
,koa2在记录日志时要手动安装koa-morgan
插件req, res, next
function loginCheck(req, res, next) {
console.log('模拟登录成功')
next()
}
复制代码
app.use()
、app.get()
、app.post()
注册中间件next()
的执行一个一个的往下串联下一个中间件实现原理思路:
app.use
用来注册中间件,先收集起来http
请求,根据path
、method
判断触发哪些中间件next()
机制,即上一个经过next()
触发下一个// 实现相似 express 的中间件
const http = require('http')
const slice = Array.prototype.slice
class LikeExpress {
constructor() {
// 收集存放中间件的列表
this.routes = {
all: [], // app.use(...)
get: [], // app.get(...)
post: [] // app.post(...)
}
}
register(path) {
const info = {}
if (typeof path === 'string') {
info.path = path
// 从第二个参数开始,转换为数组,存入 stack
info.stack = slice.call(arguments, 1)
} else {
info.path = '/'
// 从第一个参数开始,转换为数组,存入 stack
info.stack = slice.call(arguments, 0)
}
return info
}
// 中间件注册和收集
use() {
const info = this.register.apply(this, arguments)
this.routes.all.push(info)
}
get() {
const info = this.register.apply(this, arguments)
this.routes.get.push(info)
}
post() {
const info = this.register.apply(this, arguments)
this.routes.post.push(info)
}
// 经过当前 method 和 url 来匹配当前路由可执行的中间件
match(method, url) {
let stack = []
if (url === '/favicon.ico') {
return stack
}
// 获取 routes
let curRoutes = []
curRoutes = curRoutes.concat(this.routes.all)
curRoutes = curRoutes.concat(this.routes[method])
curRoutes.forEach(routeInfo => {
if (url.indexOf(routeInfo.path) === 0) {
// url === '/api/get-cookie' 且 routeInfo.path === '/'
// url === '/api/get-cookie' 且 routeInfo.path === '/api'
// url === '/api/get-cookie' 且 routeInfo.path === '/api/get-cookie'
stack = stack.concat(routeInfo.stack)
}
})
return stack
}
// 核心的 next 机制
handle(req, res, stack) {
const next = () => {
// 拿到第一个匹配的中间件
const middleware = stack.shift()
if (middleware) {
// 执行中间件函数
middleware(req, res, next)
}
}
next()
}
callback() {
return (req, res) => {
res.json = (data) => {
res.setHeader('Content-type', 'application/json')
res.end(
JSON.stringify(data)
)
}
const url = req.url
const method = req.method.toLowerCase()
const resultList = this.match(method, url)
this.handle(req, res, resultList)
}
}
listen(...args) {
const server = http.createServer(this.callback())
server.listen(...args)
}
}
// 工厂函数
module.exports = () => {
return new LikeExpress()
}
复制代码
async
函数,参数为(ctx, next)
app.use(async (ctx, next) => {
await next();
ctx.body = 'Hello World';
});
复制代码
实现思路:
app.use
来注册中间件,先收集起来next
机制,即上一个经过await next()
触发下一个中间件method
和path
的判断<!--实现相似 靠中间件-->
const http = require('http')
// 组合中间件
function compose(middlewareList) {
return function (ctx) {
function dispatch(i) {
const fn = middlewareList[i]
try {
return Promise.resolve(
fn(ctx, dispatch.bind(null, i + 1)) // promise
)
} catch (err) {
return Promise.reject(err)
}
}
return dispatch(0)
}
}
class LikeKoa2 {
constructor() {
this.middlewareList = []
}
// 收集中间件列表
use(fn) {
this.middlewareList.push(fn)
return this
}
createContext(req, res) {
const ctx = {
req,
res
}
ctx.query = req.query
return ctx
}
handleRequest(ctx, fn) {
return fn(ctx)
}
callback() {
const fn = compose(this.middlewareList)
return (req, res) => {
const ctx = this.createContext(req, res)
return this.handleRequest(ctx, fn)
}
}
listen(...args) {
const server = http.createServer(this.callback())
server.listen(...args)
}
}
module.exports = LikeKoa2
复制代码
restart
,而不是说系统出错以后其余用户就没法使用了下载安装
cnpm i pm2 -g
复制代码
配置命令
"prd": "cross-env NODE_ENV=production pm2 start app.js"
复制代码
启动
npm run prd
复制代码
经常使用命令
pm2配置文件
{
"apps": {
"name": "pm2-test-server", // 进程名
"script": "app.js", //用框架就是'bin/www'
"watch": true, // 监听文件变化,是否自动重启
"ignore_watch": [ // 哪些文件不须要重启
"node_modules",
"logs"
],
"instances": 4, // 进程个数,这里
"error_file": "logs/err.log", // 错误日志存放位置
"out_file": "logs/out.log", // 原本打印在控制台的console自定义存放在文件里
"log_date_format": "YYYY-MM-DD HH:mm:ss" // 日志的时间戳
}
}
复制代码
为什么使用多进程
多进程和redis