一. Express的简介和安装
1. Express简介
官网对这个框架的解释是:基于 Node.js 平台,快速、开放、极简的 Web 开发框架。Express的官网地址是https://www.expressjs.com.cn 。
Express的特色:
(1) Web 应用程序:Express 是一个保持最小规模的灵活的 Node.js Web 应用程序开发框架,为 Web 和移动应用程序提供一组强大的功能。
(2) API :使用您所选择的各种 HTTP 实用工具和中间件,快速方便地创建强大的 API。
(3) 性能 :Express 提供精简的基本 Web 应用程序功能,而不会隐藏您了解和青睐的 Node.js 功能。
(4) 基础框架 :许多 流行的开发框架 都基于 Express 构建。
2. 在项目中安装Express
首先我们创建一个文件夹,然后我们先要初始化一下文件夹:
npm init -y
安装express:
npm install express --save
二. Express的使用
1. 入门简单案例
我们先简单使用一下Express,学习它的简单用法,由浅入深。本文后面小节里再来学习路由、中间件、请求处理等等的功能。
新建index.js文件,然后编写如下代码:
const express = require('express') // 创建express实例 const app=express(); app.get("/",(req, res) => { res.send("hello world!"); }) app.get("/aaa",(req, res) => { res.send("aaa"); }) app.listen(3000,()=>{ console.log("server start") })
很简单吧,express创建http接口,相比Node.js的http模块来说也太方便了吧,只需要调用get()方法,然后里面传入请求的路径和回调函数就好了。而且回调里面也不用再调用res.write()和res.end()了,express封装了一个res.send()来代替。
这个小案例,我们浏览器访问相应的路径时,就会得到相应的显示:
而且,当我们访问一个我们没有定义的请求路径的时候,它会在页面上面显示出相应的错误。
我们上面说到express封装的res.send()方法,这个方法其实非常地妙,那么妙在哪里呢?下面举几个例子来体会。
我们更改一下代码,把之前请求的hello world!字符串改成html标签返回,看看会有什么效果:
const express = require('express') // 创建express实例 const app=express(); app.get("/",(req, res) => { res.send(` <html> <h1>hello world!</h1> </html> `); }) app.listen(3000,()=>{ console.log("server start") })
运行发现,它可以解析并返回html。
我们再改一下代码,看看它能不能返回json数据的接口:
const express = require('express') // 创建express实例 const app=express(); app.get("/",(req, res) => { res.send({ name:'害恶细君', age:20 }); }) app.listen(3000,()=>{ console.log("server start") })
也就是说在send()方法中传入一个对象的话,返回给前端的就是一个json字符串。
而且,express最好的地方就是:它的回调里面的req (请求) 和 res (响应) 与 Node.js 提供的对象完全一致,因此,你可以调用 req.pipe()、req.on('data', callback) 以及任何 Node 提供的方法。
2. Express基本路由
路由是指如何定义应用的端点(URIs)以及如何响应客户端的请求。
路由是由一个 URI、HTTP 请求(GET、POST等)和若干个句柄组成,它的结构如下: app.METHOD(path, [callback...], callback) , app 是 express 对象的一个实例, METHOD 是一个 HTTP 请求方法, path 是服务器上的路径, callback 是当路由匹配时要执行的函数。
路由路径和请求方法一起定义了请求的端点,它可以是字符串、字符串模式或者正则表达式。但查询字符串不是路由路径的一部分。
(1) 使用字符串的路由路径示例:
// 匹配根路径的请求 app.get('/', function (req, res) { res.send('root'); }); // 匹配 /about 路径的请求 app.get('/about', function (req, res) { res.send('about'); }); // 匹配 /test.text 路径的请求 app.get('/test.text', function (req, res) { res.send('test.text'); });
(2) 使用字符串模式的路由路径示例(下面第1个使用得最多):
// 匹配 /ab/****** app.get('/ab/:id', function(req, res) { res.send('aaaaaaa'); }); // 匹配 acd 和 abcd app.get('/ab?cd', function(req, res) { res.send('ab?cd'); }); // 匹配 abcd、abbcd、abbbcd等 app.get('/ab+cd', function(req, res) { res.send('ab+cd'); }); // 匹配 abcd、abxcd、abRABDOMcd、ab123cd等 app.get('/ab*cd', function(req, res) { res.send('ab*cd'); }); // 匹配 /abe 和 /abcde app.get('/ab(cd)?e', function(req, res) { res.send('ab(cd)?e'); });
(3) 使用正则表达式的路由路径示例:
// 匹配任何路径中含有 a 的路径: app.get(/a/, function(req, res) { res.send('/a/'); }); // 匹配 butterfly、dragonfly,不匹配 butterflyman、dragonfly man等 app.get(/.*fly$/, function(req, res) { res.send('/.*fly$/'); });
可以为请求处理提供多个回调函数,其行为类似 中间件。唯一的区别是这些回调函数有可能调用 next(‘route’) 方法而略过其他路由回调函数。可以利用该机制为路由定义前提条件,如果在现有路径上继续执行没有意义,则可将控制权交给剩下的路径。
路由句柄有多种形式,可以是一个函数、一个函数数组,或者是两者混合,如下所示.
(1) 使用多个回调函数处理路由(记得指定 next 对象):
const express = require('express') app.get('/example/b', function (req, res, next) { console.log('response will be sent by the next function ...'); next(); }, function (req, res) { res.send('Hello from B!'); }); app.listen(3000,()=>{ console.log("server start") })
(2) 使用回调函数数组处理路由:
const express = require('express') // 创建express实例 const app=express(); let cb0 = function (req, res, next) { console.log('CB0') next() } let cb1 = function (req, res, next) { console.log('CB1') next() } let cb2 = function (req, res) { res.send('Hello from C!') } app.get('/test', [cb0, cb1, cb2]) app.listen(3000,()=>{ console.log("server start") })
(3) 混合使用函数和函数数组处理路由:
const express = require('express') // 创建express实例 const app=express(); let cb0 = function (req, res, next) { console.log('CB0') next() } let cb1 = function (req, res, next) { console.log('CB1') next() } app.get('/test', [cb0, cb1], function (req, res, next) { console.log('response will be sent by the next function ...') next() }, function (req, res) { res.send('Hello from D!') }) app.listen(3000,()=>{ console.log("server start") })
3. 中间件的用法
Express 是一个自身功能极简,完全是由路由和中间件构成一个的 web 开发框架:从本质上来说,一个 Express 应用就是在调用各种中间件。
中间件(Middleware) 是一个函数,它可以访问请求对象(request object (req)), 响应对象(response object (res)), 和 web 应用中处于请求-响应循环流程中的中间件。
中间件的功能包括:执行任何代码、修改请求和响应对象、终结请求-响应循环、调用堆栈中的下一个中间件。
如果当前中间件没有终结请求-响应循环,则必须调用 next() 方法将控制权交给下一个中间件,否则请求就会挂起。
Express 应用可使用如下几种中间件:
(1) 应用级中间件
(2) 路由级中间件
(3) 错误处理中间件
(4) 内置中间件
(5) 第三方中间件
(1) 应用级中间件
应用级中间件绑定到 app 对象 使用 app.use() 和 app.METHOD(), 其中, METHOD 是需要处理的 HTTP 请求的方法,例如 GET, PUT, POST 等等,全部小写。例如:
const express = require('express') // 创建express实例 const app=express(); // 没有挂载路径的中间件,应用的每个请求都会执行该中间件 app.use(function (req, res, next) { console.log('Time:', Date.now()) next() }) // 挂载至 /user/:id 的中间件,任何指向 /user/:id 的请求都会执行它 app.use('/user/:id', function (req, res, next) { console.log('Request Type:', req.method) next() }) // 路由和句柄函数(中间件系统),处理指向 /user/:id 的 GET 请求 app.get('/user/:id', function (req, res, next) { res.send('USER') }) app.listen(3000,()=>{ console.log("server start") })
下面这个例子展示了在一个挂载点装载一组中间件。
const express = require('express') // 创建express实例 const app=express(); // 一个中间件栈,对任何指向 /user/:id 的 HTTP 请求打印出相关信息 app.use('/user/:id', function(req, res, next) { console.log('Request URL:', req.originalUrl) next() }, function (req, res, next) { console.log('Request Type:', req.method) next() }) app.listen(3000,()=>{ console.log("server start") })
作为中间件系统的路由句柄,使得为路径定义多个路由成为可能。在下面的例子中,为指向 /user/:id 的 GET 请求定义了两个路由。第二个路由虽然不会带来任何问题,但却永远不会被调用,因为第一个路由已经终止了请求-响应循环。
const express = require('express') // 创建express实例 const app=express(); // 一个中间件栈,处理指向 /user/:id 的 GET 请求 app.get('/user/:id', function (req, res, next) { console.log('ID:', req.params.id) next() }, function (req, res, next) { res.send('User Info') }) // 处理 /user/:id, 打印出用户 id (因为第一个路由已经终止了请求-响应循环,故它不会被调用) app.get('/user/:id', function (req, res, next) { res.end(req.params.id) }) app.listen(3000,()=>{ console.log("server start") })
如果需要在中间件栈中跳过剩余中间件,调用 next(‘route’) 方法将控制权交给下一个路由。
const express = require('express') // 创建express实例 const app=express(); // 一个中间件栈,处理指向 /user/:id 的 GET 请求 app.get('/user/:id', function (req, res, next) { // 如果 user id 为 0, 跳到下一个路由 if (req.params.id == 0) next('route') // 否则将控制权交给栈中下一个中间件 else next() // }, function (req, res, next) { res.send('aaa') }); // 处理 /user/:id, app.get('/user/:id', function (req, res, next) { res.send('bbb') }) app.listen(3000,()=>{ console.log("server start") })
(2) 路由级中间件
路由级中间件和应用级中间件一样,只是它绑定的对象为 express.Router()
,然后app.use('/', router)
将路由挂载至应用
const router = express.Router()