一、前言
基于 Node.js 平台,快速、开放、极简的 Web 开发框架 。
1. 框架的作用
框架可以帮助省略掉一些基本的相同底层代码的反复书写,只需调用框架的方法就可以实现你想要的功能。
回顾一下 Node - 002 - 搭建一个Web服务 和 Node - 003 - Web服务升级 这两篇文章。写原生实现总是非常繁琐且费时的。
2. Node 相关的框架
- express
- koa
- egg
- thinkjs
- adonisjs
nestjs
…..
二、安装
$ npm install express
三、Hello World
const express = require('express');const app = express();app.get('/', function(req, res) {res.send('hello world');});app.listen(3000, () => {console.log('服务启动成功! http://localhost:3000');});
四、路由
路由是指确定应用程序如何响应客户端(浏览器)对特定端点的请求,该特定端点是URL(或路径)和特定的HTTP请求方式(GET、POST等)。 每个路由可以具有一个或多个处理程序函数,这些函数在路由匹配时执行。
1. 路由的基本语法
app.METHOD(PATH, [...HANDLER])
- app 是 express 的实例。
- METHOD 是小写的 HTTP 请求方式(GET、POST、PUT、PATCH、DELETE等)。
- PATH 是请求路径。(以 / 开头)
- HANDLER 是当路由匹配时执行的函数。
// 1. 处理 GET / 请求时app.get('/', (req, res) => {res.send('GET / 响应')})// 2. 处理 POST / 请求时app.post('/', (req, res) => {res.send('POST / 响应')})// 3. 处理 GET /users 请求时app.get('/users', (req, res) => {res.send('GET /users 响应')})// 4. 处理 DELETE /users 请求时app.delete('/users', (req, res) => {res.send('DELETE /users 响应')})
2. 请求参数的获取
- query 参数(?号传参)
Route Path : /helloRequest URL : http://localhost:3000/hello?name=zhangsan&age=18req.query : { name: 'zhangsan', age: '18' }
- body 参数(请求体传参)
注意:req.body 需要设置中间件
const express = require('express')const bodyParser = require('body-parser')const app = express()/*** 处理 请求体参数的 解析* Express 4.16.0 之前使用 bodyParser 第三方模块*/app.use(bodyParser.json())app.use(bodyParser.urlencoded({ extended: true }))/*** 处理 请求体参数的 解析。* Express 4.16.0 起 提供了内置的 express.json() 和 express.urlencoded()* 当然他们内部还是基于 bodyParser 的*/// app.use(express.json())// app.use(express.urlencoded({ extended: true }))app.post('/login', (req, res) => {console.log(req.body)res.send('POST /login 响应')})app.listen(3000, () => {console.log('服务启动成功')})
Route Path : /loginRequest URL : http://localhost:3000/loginRequest BODY: username=lisi&password=123456或者 { username: 'lisi', password: '123456' }req.body : { username: 'lisi', password: '123456' }
- params 参数(动态路径传参)
Route Path : /users/:userId/books/:bookIdRequest URL : http://localhost:3000/users/34/books/8989req.params : { userId: '34', bookId: '8989' }
3. 路由处理函数
路由处理函数是一种类似于 中间件函数 的方法。一个路由可以同时设置多个路由处理函数。
接收三个参数:
- req:request 请求对象
- res:response 响应对象
- next:调用它执行下一个匹配的路由处理函数
路由处理函数的多种组合形式:
// 1. 单个回调函数的形式app.get('/example/a', (req, res) => {res.send('GET /example/a 响应')})// 2. 多个回调函数以参数列表形式,注意 next 回调app.get('/example/b', (req, res, next) => {console.log('1')next()}, (req, res, next) => {console.log('2')res.send('GET /example/b 响应')})// 3. 多个回调函数以数组形式,注意 next 回调app.get('/example/c', [(req, res, next) => {console.log('CB-1')next();},(req, res, next) => {console.log('CB-2')next();},(req, res, next) => {res.send('GET /example/c 响应')}])// 4. 组合形态app.get('/example/d', [(req, res, next) => {console.log('CB-1')next();},(req, res, next) => {console.log('CB-2')next();},], (req, res, next) => {res.send('GET /example/d 响应')})
4. express.Router
使用 express.Router 类来创建模块化的,可安装的路由处理程序。一个 Router 实例是一个完整的中间件和路由系统。
思考如下代码:
当项目做大做强时,index.js 文件将异常庞大。不利于后续的项目维护。
// index.jsconst express = require('express')const app = express()app.get('/', (req, res) => { res.send('GET / 响应') })app.get('/posts', (req, res) => { res.send('GET /posts 响应') })app.post('/posts', (req, res) => { res.send('POST /posts 响应') })app.get('/posts/create', (req, res) => { res.send('GET /posts/create 响应') })app.get('/posts/:id', (req, res) => { res.send('GET /posts/xxid 响应') })app.put('/posts/:id', (req, res) => { res.send('PUT /posts/xxid 响应') })app.get('/posts/:id/edit', (req, res) => { res.send('GET /posts/xxid/edit 响应') })app.delete('/posts/:id', (req, res) => { res.send('DELETE /posts/xxid 响应') })app.get('/books', (req, res) => { res.send('GET /books 响应') })app.post('/books', (req, res) => { res.send('POST /books 响应') })app.get('/books/create', (req, res) => { res.send('GET /books/create 响应') })app.get('/books/:id', (req, res) => { res.send('GET /books/xxid 响应') })app.put('/books/:id', (req, res) => { res.send('PUT /books/xxid 响应') })app.get('/books/:id/edit', (req, res) => { res.send('GET /books/xxid/edit 响应') })app.delete('/books/:id', (req, res) => { res.send('DELETE /books/xxid 响应') })app.listen(3000)
这时就可以将相同类别的路由处理代码抽离到单独的文件中,最后在主程序(这里指 index.js)中加载。比如:
- 抽离 posts 相关的存放到 routes/posts.js 文件中
// routes/posts.jsconst express = require('express')const router = express.Router()router.get('/', (req, res) => { res.send('GET /posts 响应') })router.post('/', (req, res) => { res.send('POST /posts 响应') })router.get('/create', (req, res) => { res.send('GET /posts/create 响应') })router.get('/:id', (req, res) => { res.send('GET /posts/xxid 响应') })router.put('/:id', (req, res) => { res.send('PUT /posts/xxid 响应') })router.get('/:id/edit', (req, res) => { res.send('GET /posts/xxid/edit 响应') })router.delete('/:id', (req, res) => { res.send('DELETE /posts/xxid 响应') })// 不要忘了暴露出去module.exports = router
- 抽离 books 相关的存放到 routes/books.js 文件中
// routes/books.jsconst express = require('express')const router = express.Router()router.get('/', (req, res) => { res.send('GET /books 响应') })router.post('/', (req, res) => { res.send('POST /books 响应') })router.get('/create', (req, res) => { res.send('GET /books/create 响应') })router.get('/:id', (req, res) => { res.send('GET /books/xxid 响应') })router.put('/:id', (req, res) => { res.send('PUT /books/xxid 响应') })router.get('/:id/edit', (req, res) => { res.send('GET /books/xxid/edit 响应') })router.delete('/:id', (req, res) => { res.send('DELETE /books/xxid 响应') })// 不要忘了暴露出去module.exports = router
- 在主程序中(index.js)中引入并使用
// index.jsconst express = require('express')// 引入const postsRouter = require('./routes/posts.js')const booksRouter = require('./routes/books.js')const app = express()app.get('/', (req, res) => { res.send('GET / 响应') })// 使用app.use('/posts', postsRouter)app.use('/books', booksRouter)app.listen(3000)
