系統架構設計的四層抽象: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