Node.js服务端编程及架构模式(学习笔记)
- Node.js 介绍
- WEB服务端开发入门
- 框架及架构模式介绍
Node.js是什么
- 基于Chrome v8
- 事件驱动,非堵塞 I/O
- npm
Node.js 服务端开发的兴起
- 大量WEB应用需求
- Node.js 性能足够好
- 全站工程师更利于人员合理调配
- 丰富的生态 ,较高的开发效率
前端同学如何写Node.js 服务?
- 跟浏览器打交道,兼容性问题
- 组件化设计
- 加载速度 js性能执行 渲染性能
- 错误监控
- XSS CSRF 等安全漏洞
角色转变
- 数据库 Redis 等周边服务
- 性能 内存泄漏 CPU 机器管理
- 性能监控 错误监控 流量监控 报警
- SQL 注入 目录遍历等安全问题
章节
- WEB服务端开发
WEB服务端开发入门
- HTTP网络协议
- Node.js 模块及其接口设计
简单的WEB 应用框架
前端 | 后端
client > HTTP < WEB Server
应用程序就是接受HTTP请求并返回 HTTP响应的函数
unction app(httpRequest) {
// application code
return httpResponse;
}
但现实中函数一般如下
function app(httpRequest, httpResponse) {
// application code
httpResponse.end()
}
HTTP over TCP/IP
浏览器浏览网址的过程
打开www.baidu.com URL
浏览器解析URL的IP DNS
HTTP请求 (GET HTTP/1.1 headers payload) TCP/IP
HTTP响应 (HTTP/1.1 200 OK headers Content-Length: 12 Hello world!)
使用TCP处理HTTP请求
github 源码地址
HTTP基于TCP
- TCP基于字节流没有定义边界
- HTTP协议定义边界
- HTTP 是无状态的 fire and forget
function app(socket: net.Socket) {
// application code
socket.end();
}
function app(httpRequest, httpResponse) {
// application code
httpResponse.end()
}
http echo server
Yap!Stream
import * as http from 'http'
http.createServer((request, response) => {
const { headers, method, url } = request;
response.writeHead(200, { 'Content-Type': 'application/json' })
response.write(JSON.stringify({ headers, method, url }, null, 2));
request.pipe(response);
}).listen(7500, function () {
console.log('opened server on', this.address());
})
tcp是基于字节流的 ,udp基于报文
小结
request headers 和body 如何获取?
1:headers 可以直接获取
2:body 需要自己解析(data,end event)
request 和 response 为什么分开?
- HTTP对请求响应头规范不一样
- socket有双工和弹弓,需要拍拆分接口
request 和response 共享一个 socket
HTTP(S) 网络协议进阶
request methods
HTTP状态吗
- 200
- 302
- 304
- 403
- 404
- 500
HTTP Headers
- Access COntrol
- Cache Control
- Authentication
- Cookie
- Security
- 。。。
如何实现一个静态服务器?
MIME
上面有源码链接
import * as fs from 'fs'
import * as http from 'http'
import * as path from 'path'
内容协商
import * as http from 'http';
import * as json2html from 'node-json2html';
// 内容协商
如何控制缓存?
URl 后面加上时间戳就可以去掉缓存了,棒
缓存策略
Cache-Control
- 又称强缓存 普通刷新忽略他,但并不会清楚它 ,需要强制刷新
- 浏览器强制刷新,请求会带上Cache-control:no-cache 和 Pragma : no-cache
协商缓存
- 又称若缓存 ,普通刷新会岂容若缓存,忽略强缓存
- 只有从地址栏或收藏夹输入地址,通过链接引用资源等情况下,浏览器才会启用强缓存
- 这是也是为什么有时候我们更新一张图片,一个js文件,内容依然是旧的,但是直接浏览器访问那个图片或者文件,看到的内容确实新的。
协商缓存时间为一天
import * as http from 'http';
import * as fs from 'fs';
import getMimeType from './get-mime-type';
小结
- 介绍HTTP协议
- 下来可回忆根据讲义链接自行学习
- 客户端开发对协议感受不那么明显
- 深入了解HTTP协议才能开发出合理的ERB服务
- 实现i 个静态服务器
- 介绍缓存并实现简单的策略
补充: 浏览器常见的网络协议
- HTTP
- WebSocket
- WebRTC
- DNS QUIC FTP SMTP
- 。。。
框架及架构模式介绍
我们面临的挑战
- 复杂的业务逻辑
- 服务横向扩展
- 异常处理
- 回调地狱
框架 + 合理的架构
Web服务器通用处理流程
Core J2EE Patterns - Intercepting Filter
public class DebuggingFilter implements Processor {
private Processor target;
public DebuggingFilter(Processor myTarget) {
target = myTarget;
}
public void execute(ServletRequest req,
ServletResponse res) throws IOException,
ServletException {
// preprocess
target.execute(req, res);
// post-process
}
}
- 提高重用行
- 声明式的配置
- XML 灵活配置不通过路由的FIlter
- Filter之间难以共享数据
- Filter 和核心业务逻辑分开
Node.js 服务端框架
- Express
- Kos
- ThinkJs
Express
- Routing
- Middleware
var express = require('express');
var app = express();
app.get('/', function(req, res, next) {
next();
})
app.listen(7500);
express.Router
/*
文件 bird.js
*/
var express = require('express')
var router = express.Router()
// middleware that is specific to this router
router.use(function timeLog (req, res, next) {
console.log('Time: ', Date.now())
next()
})
// define the home page route
router.get('/', function (req, res) {
res.send('Birds home page')
})
// define the about route
router.get('/about', function (req, res) {
res.send('About birds')
})
从链式到树的提升
chain of responsitility
Express 特点总结
优点
- 简单 框架级自带好用的路由,丰富的生态
缺点
- 回调 拦截处理不好实现
Koa.js
使用async functon, Node 7.6 及以上
异步中间件模型-洋葱模型
const Koa = require('koa');
const app = new Koa();
app.use(async ctx => {
ctx.body = 'Hello World';
});
app.listen(7500);
异步中间件模型
中间件的执行顺序
Koa特点总结
优点
- 支持最新Aync语法
- 性能和express相当
- 异步中间件模型更加先进
不足 - 只提供了中间件模型及http 的最小封装
ThinkJS 3
企业级Web MVC 框架
- 基于Koa2.x 兼容middleware
- 内核小巧 支持Extend Adapter 等插件方式
- 性能优异 单元测试覆盖程度高
- 内置自动编译 自动更新机制 方便快速开发
- 使用更优雅的 async / await 处理异步问题
- 从3.2 开始支持TypeScript
ThinkJS 架构
ThinkJS 架构模式
- MVC 模式 分离视图模型
- IoC 模式 减少耦合 增加程序的可扩展性
MVC 架构模式
MVC 代码
// src/controller/user.js
module.exports = class extends think.Controller {
async indexAction() {
const users = await this.model('user').getList(); // 调用 model
this.assign('users',users); //给模板赋值
return this.display(); //渲染模板
}
}
// src/model/user.js
module.exports = class extends think.Model {
getList() {
return this.field('name').select();
}
}
///view/user.html
Hello #{users[0].name}!
IoC 依赖反转
场景:
- 服务端session 实现 前期单台服务器存到文件就够用了,后期上redies
目标
- 不需要修改业务逻辑的代码实现替换 (依赖注入DI)
- 不需要关注服务的创建和声明周期(IoC容器)
IoC模式实现
ThinkJS extend adapter
简单对比
框架 | Express | Koa | ThinkJS |
---|---|---|---|
Router | ✓ | ✓ |
|
Promise | ✓ | ✓ |
|
Templating | ✓ | ✓ |
|
Enterprise | ✓ | ✓ |
|
MVC | ✓ |
||
IoC | ✓ |
||
TypeScript | ✓ | ✓ | ✓ |
多模块 | ✓ | ✓ |
我们要不要用企业级别框架?
- 数据校验
- 安全漏洞
- Cluster 多进程
- 故障自恢复
- 开发体验
- 接口一致性
- 文档积累
最快速度收获最佳实践
小结
介绍对比了三个框架
- express
- Koa
- ThinkJS
介绍几个架构模式
- middleware
- interceptor
- 异步中间件模式
- chain of responsitlity
- MVC
- IoC