web 框架指的是處理 http、https 的服務端框架,Node.js 提供了 http、https 模塊用於處理協議數據,這是 web 框架的基礎。
但是 http、https 的 api 過於簡單,用起來比較麻煩,所以一般會用 express、koa、fastify 這種封裝了一層的框架來簡化。
但 express 類的框架不提供代碼架構方面的限制,所以對於模塊比較多比較複雜的企業級應用來說並不適合,這時就要用實現了 MVC 的 eggjs、nestjs 這類企業級 web 框架。
這是 web 框架的 3 個層次,理清了它們的關係和適用場景,再去學習纔不會迷茫。
下面我們分別來看一下:
http 是基於 TCP 的,對 TCP 傳過來的 http 協議數據做 parse,傳給 handler 處理,handler 處理完要返回 http 響應,這是 http 模塊做的事情。
const http = require('http'); const server = http.createServer((req, res) => { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('okay'); }); server.listen(8080, '127.0.0.1');
http 模塊雖然能處理請求和響應,但是提供的 api 過於原始:
比如獲取請求參數還要用 url 模塊 parse 一次
const http = require('http'); const url = require('url'); http.createServer(function (req, res) { const queryObject = url.parse(req.url,true).query; console.log(queryObject); res.writeHead(200, {'Content-Type': 'text/html'}); res.end('xxx'); }).listen(8080);
比如返回響應只能用 write 或者 end 返回一段 buffer 或 string,想返回 JSON、文件下載、html 視圖等都要自己實現。
而且 get、post、put、delete 等請求類型也要自己做判斷。
if(req.method === 'get') { //... } else if (req.method === 'post') { //... } //...
因爲有這些痛點,所以一般我們不會直接用 http 模塊,而是用封裝了一層的 express、koa、fastify 這類 web 框架。
express 這類框架解決了剛纔的那個痛點問題:
提供了路由機制,不用自己手動判斷 method 和 path
app.get('/list', function (req, res) { //... }) app.post('/save', function(req, res) { //... })
提供了更好用的 request 和 response api:
比如 req.params 獲取請求參數
app.get('/user/:id', function (req, res) { res.send('user ' + req.params.id) }) res.download 返回下載的響應 res.download('/report-12345.pdf') res.render 返回模版引擎渲染的 html app.render('xxx-template', { name: 'guang' }, function (err, html) { // ... })
提供了中間件機制,用於複用一些一些邏輯:
比如文件上傳中間件
app.use(fileUpload({ useTempFiles : true, tempFileDir : '/tmp/' }));
提供了這麼多方便的功能,確實比 http 模塊用起來簡單多了。
但是 express 類的 web 框架也有問題,就是沒有提供組織代碼的模式,當模塊多了代碼很容易亂掉,因爲它只是按照類似洋蔥的順序調用中間件,沒有模塊和 MVC 的劃分。
express 類框架做一些小的服務可以,企業級應用還得用 nestjs、eggjs 這類 MVC 框架。
nestjs 類的框架就實現了 MVC 的模式,代碼有明顯的 Controller、Service、Model、View 的劃分:
import { Body, Controller, Delete, Get, Param, Post } from '@nestjs/common'; import { CreateUserDto } from './dto/create-user.dto'; import { User } from './user.entity'; import { UsersService } from './users.service'; @Controller('users') export class UsersController { constructor(private readonly usersService: UsersService) {} @Post() create(@Body() createUserDto: CreateUserDto): Promise { return this.usersService.create(createUserDto); } @Get() findAll(): Promise { return this.usersService.findAll(); } @Get(':id') findOne(@Param('id') id: string): Promise { return this.usersService.findOne(id); } @Delete(':id') remove(@Param('id') id: string): Promise { return this.usersService.remove(id); } }
nestjs 是對標 java 的 spring 的,實現了 IOC、AOP 等模式,模塊之間耦合度很低,就算再複雜的項目,通過 Module、Controller、Service 等也可以很好的被組織起來,相比 express 來說,組織代碼方面提升了一個檔次。
nestjs 的底層就是 express、fastify 等 web 框架,而且還可以靈活的切換底層實現。
可以看到,nestjs、eggjs 類的企業級框架,除了有豐富的 api 以外,更重要的是提供了代碼組織的規範,通過 Module、Controller、Service 等概念可以很好的組織複雜的業務邏輯。
web 框架都是基於 http、https 模塊,但它提供的 api 過於原始,使用起來比較麻煩,所以我們一般會用 express、koa 這類框架來簡化,它提供了中間件機制來複用邏輯,提供了更多的 request、response 的 api,但卻沒有組織複雜代碼的能力,對於企業級的複雜應用,還是會用 nestjs、eggjs 這類 MVC 框架,它們的底層是 express、koa,但提供了 Module、Controller、Service 等概念,可以很好的組織複雜的代碼。
要理清楚爲什麼會有這三個層次,都各自適合什麼場景,這樣才能更好的掌握它們,在技術選型上纔不會迷茫。