1.7 express
- 官方给出的概念:Express 是基于 Node.js 平台,快速、开发、极简的 Web 开发框架。通俗易懂的理解:Express 的作用和 Node.js 内置的 http 模块类似,是专门用来创建 Web 服务器
npm i express -S
1.7.1 创建基本的 web 服务器
// 1. 导入 express
const express = require('express');
// 2. 创建 web 服务器
const app = express();
// 3. 调用 app.listen(端口号, 启动成功之后的回调函数),启动服务器
app.listen(80, () => {
console.log('express server running at http://127.0.0.1');
})
1.7.2 监听请求
-
监听 GET 请求
- 通过
app.get()方法,监听客户端的 GET 请求,具体语法格式如下:
/** * app.get('请求的URL', (req, res) => { 处理函数 }) * 参数1:请求的URL * 参数2:请求所对应的回调函数 * req:请求对象(包含了与请求相关的属性和方法) * res:响应对象(包含了与响应相关的属性和方法) */ app.get('/list', (req, res) => { const data = { "name": "胖丁", "age": 22, }; res.send(data); }); - 通过
-
监听 POST 请求
- 通过
app.post()方法,监听客户端的 POST请求,具体语法格式如下:
/** * app.post('请求的URL', (req, res) => { 处理函数 }) * 参数1:请求的URL * 参数2:请求所对应的回调函数 * req:请求对象(包含了与请求相关的属性和方法) * res:响应对象(包含了与响应相关的属性和方法) */ app.post('/user', (req, res) => { const data = { "name": "胖丁", "age": 22, }; res.send(data); }); - 通过
-
将内容响应给客户端
- 通过
res.send()
// 1、 导入 express const express = require('express'); // 2. 创建 web 服务器 const app = express(); // 4. 监听客户端的 GET 和 POST 请求,并向客户端响应具体的内容 app.get('/user', (req, res) => { // 调用 express 提供的 res.send() 方法,向客户端响应一个 JSON 对象 res.send({"name": "zs", "age": 22, "gender": "男"}); }); app.post('/user', (req, res) => { // 调用 express 提供的 res.send() 方法,向客户端响应一个 文本字符串 res.send('请求成功'); }); // 3. 启动 web 服务器 app.listen(80, ()=> { console.log('express server running at http://127.0.0.1'); }); - 通过
-
获取 URL 中携带的查询参数
- 通过 req.query 对象,可以访问到客户端通过查询字符串的形式,发送到服务器的参数
app.get('/list', (req, res) => { /** * req.query 默认是一个空对象 * 客户端使用 ?name=zs&age=22 这种查询字符串形式,发送到服务器的参数 */ console.log(req.query, 'query'); });http://127.0.0.1/list?name=芳芳&age=22 // 客户端的请求 -
获取 URL 中的动态参数
- 通过
req.params 对象,可以访问到 URL 中,通过 : 匹配到的动态参数
app.get('/home/:id/:name', (req, res) => { /** * req.params 默认是一个空对象, 里面存放着通过 : 动态匹配到的参数值 * 客户端请求 /1/芳芳 */ console.log(req.params); res.send(req.params); });http://127.0.0.1/home/1/芳芳 - 通过
-
托管静态资源
- 通过
express.static()我们可以非常方便地创建一个静态资源服务器,例如,通过如下代码就可以将 public 目录下的图片、CSS 文件、JavaScript 文件对外访问
app.use(express.static('public')); // 'publice' 文件夹名- 注意:Express 在指定的静态目录中查找文件,并对外提供资源的访问路径。因此,存放静态文件的目录名不会出现在 URL 中
http://129.0.0.1/index.js http://129.0.0.1/index.css http://129.0.0.1/index.html http://129.0.0.1/image- 托管多个静态资源目录
app.use(express.static('public')); app.use(express.static('file')); // 访问静态资源文件时,express.static() 函数会根据目录的添加查询所需的文件- 挂载路径前缀
app.use('/file', express.static('public')) http://129.0.0.1/file/index.js http://129.0.0.1/file/index.css http://129.0.0.1/file/index.html http://129.0.0.1/file/image - 通过
1.8 路由
1.8.1 路由注册
// 导出路由模块
const router = require('./router');
// 注册路由模块
app.use(router);
// 注:统一给路由添加前缀 /api 就是统一添加的前缀
// app.use('/api', router)
1.8.2 创建路由模块
const express = require('express'); // 1. 导入 express
const router = express.Router(); // 2. 创建路由对象
router.get('/user/list', function(req, res){ // 3. 挂载获取用户列表的路由
res.send('Get user list');
})
router.post('/user/add', function(req, res){ // 4. 挂载添加用户的路由
res.send('Add new user');
})
module.exports = router // 5. 向外导出路由对象
const express = require('express');
const userRouter = require('./02.user.js');
const app = express();
app.use(userRouter);
app.listen(80, ()=> {
console.log('express server running at http://127.0.0.1');
});
1.8.3 Express 中间件
-
Express 中间件的调用流程
- 当一个请求到达 Express 的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理

-
Express 中间件本质上就是一个 function 处理函数,Express 中间件的格式如下:
const express = require('express'); const app = express(); app.get('/', (req, res, next) => { res.data = { name: '胖丁', age: 22, } next(); // 中间件函数的形参列表中,必须包含 next 函数 // next 函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由 }); app.get('/', (req, res) => { res.data.hobby = '吃饭', res.send(res.data); }); app.get('/user', (req, res) => { res.send(res.data || 'res.data 是空的'); }); app.listen('80', () => { console.log('express server running at http://127.0.0.1'); });express 中间件和路由之间的区别:中间件函数的形参列表中,必须包含next函数,而路由处理函数中只包含req和res;next函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由
-
全局生效的中间件
- 客户端发起的任何请求,到达服务器之后,都会触发的中间件,叫做全局生效的中间件通过调用
app.use(中间件函数),即可定义一个全局生效的中间件,示码如下:
const mw = (req, res, next) { console.log('这是一个简单的中间件函数'); next(); }; // 全局生效的中间件 app.use(mw)- 中间件的作用:多个中间件之间,共享同一份 req 和 res 。基于这样的特性,我们可以在上游的中间件中,统一为 req 或 res 对象添加自定义的属性或方法,供下游的中间件或路由进行使用
- 客户端发起的任何请求,到达服务器之后,都会触发的中间件,叫做全局生效的中间件通过调用
-
局部生效的中间件
- 不使用 app.use() 定义的中间件,叫做局部生效的中间件,示码如下:
// 定义中间件函数 const mw = function(req, res, next){ console.log('这是中间件函数'); next() }; const mw1 = function(req, res, next){ console.log('这是中间件函数1'); next() }; // 局部中间件的调用 app.get('/', mw, (req, res) => { res.send('Home page'); }); // 多个局部中间件的调用 app.post('/', mw, mw1, (req, res) => { res.send('Home page'); }); app.get('/user', (req, res) => { res.send('User page'); });- 定义多个局部中间件
app.get('/', mw1, mw2, (req, res) => { res.send('Home page'); }); app.get('/', [mw1, mw2], () => { res.send('Home page'); })-
了解中间件的5个使用注意事项:
- 一定要在路由之前注册中间件
- 客户端发送过来的请求,可以连续调用多个中间件进行处理
- 执行完中间件的业务代码之后,不要忘记调用 next() 函数
- 为了防止代码逻辑混乱,调用 next () 函数后不要再写额外的代码
- 连续调用多个中间件时,多个中间件之间,共享 req 和 res 对象
-
中间件的分类
-
应用级别的中间件
-
路由级别的中间件
-
错误级别的中间件
- 错误级别的中间件的作用:专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题
- 注意:错误级别的中间件,必须注册在所有路由之后,在路由执行之后发生抛出错误会跳出往后查找错误级别的中间件
app.get('/', function(req, res) => { throw new Error('服务器内部发生了错误'); // 抛出一个错误 res.send('Home page'); }); app.use((err, req, res, next) => { // 错误级别的中间件 console.log('发生了错误:' + err.message); // 在服务器打印错误的消息 res.send('Error:' + err.message); // 想客户端相应错误的相关的内容 })
-
-
自定义中间件
-
监听 req 的 data 事件
- 监听 req 的 data 事件,来获取客户端发送到服务器的数据
-
监听 req 的 end 事件
-
监听 querystring 模块解析请求体数据
- Node,js 内置了一个 querystring 模块,专门用来处理查询字符串,通过这个模块提供的 parse() 函数,可以轻松把查询字符串,解析成对象的格式
const qs = require('querystring'); const body = qs.parse(str); -
将解析出来的数据对象挂载为 res.body
-
将自定义中间件封装为模块
const express = require('express'); // 导入 node.js 内置的 querystring 模块 const qs = require('querystring'); const app = express(); app.use((req, res, next) => { // 定义中间件具体的业务逻辑 let str = ''; // 监听 req 的 data 事件 req.on('data', (chunk) => { // 拼接请求体数据,隐式转换为字符串 str += chunk }); // 监听 req 的 end 事件 req.on('end', () => { const body = qs.parse(str); req.body = body; next() }) }); -
1.9 CORS 跨域资源共享
// 运行 npm install cors 安装中间件
npm i cors
// 使用 const cors = require('cors') 导入中间件
const cors = require('cors')
// 在路由之前调用 app.use(cors()) 配置中间件
app.use(cors())
/**
* 使用 CORS 中间件解决跨域问题
* 运行 npm install cors 安装中间件
* 使用 const cors = require('cors') 导入中间件
* 在路由之前调用 app.use(cors()) 配置中间件
*/
// CORS 响应头部 Access-Control-Allow-[Origin]
/**
* Access-Control-Allow-Origin: <origin> | *
* origin 参数的值指定了允许访问该资源的外域 URL
* 例如:res.setHeader('Access-Control-Allow-Origin', 'http://itcast.cn) 表示只能让传智播客的网页访问
* '*' 表示跨域让任何域的网站访问
*
* Access-Control-Allow-Headers
* 默认情况下,CORS 仅支持客户端想服务器发送 9 个请求头
* 如果客户端想向服务器发送额外的请求头信息,则需要服务器,通过 Access-Control-Allow-Headers 对额外的请求头进行声明
* res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Custom-Header')
*
* Access-Control-Allow-Methods
* 默认情况下,CORS 仅支持客户端发起的 GET POST HEAD 请求
* 如果客户端希望通过 PUT DELETE 等方式请求服务器的资源,则需要在服务器,通过 Access-Content-Allow-Methods 来指明实际请求所允许使用的 HTTP 方法
* 只允许 POST GET DELETE HEAD 请求方法 res.setHeader('Access-Control-Allow-Methods', 'POST, GET, DELETE, HEAD')
* 允许所有的 HTTP 请求方法 res.setHeader('Access-Control-Allow-Methods', '*')
**/
1.10 编写 jsonp 接口
app.get('/api/jsonp', (req, res) => {
console.log('111');
// 1. 获取客户端发送过来的回调函数的名字
const funcName = req.query.callback;
// 2. 得到要通过 JSONP 形式发送给客户端的数据
const data = {
name: '胖丁',
age: 22,
};
// 3. 根据前两步得到的数据,拼接出一个函数调用的字符串
const scriptStr = `${funcName}(${JSON.stringify(data)})`;
// 4. 把上一步拼接得到的字符串,响应给客户端
res.send(scriptStr)
});
- HTML 部分
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="https://cdn.staticfile.org/jquery/1.10.0/jquery.min.js"></script>
<body>
<button id="btnGET">GET</button>
<button id="btnPOST">POST</button>
<button id="btnJSONP">JSONP</button>
</body>
<script>
$('#btnPOST').on('click', () => {
$.ajax({
type: 'POST',
url: 'http://127.0.0.1/api/post',
data: {
name: '胖丁',
age: '26'
},
success: (res) => {
console.log(res);
}
})
})
$('#btnGET').on('click', () => {
$.ajax({
type: 'get',
url: 'http://127.0.0.1/api/get',
data: {
name: '芳芳',
age: '21'
},
success: (res) => {
console.log(res);
}
})
})
$('#btnJSONP').on('click', () => {
console.log('我被调用了');
$.ajax({
type: 'get',
url: 'http://127.0.0.1/api/jsonp',
dataType: 'jsonp',
// data: {
// name: '胖丁',
// age: '26'
// },
success: (res) => {
console.log( 'res', res);
}
})
})
</script>
</html>
Node 开发好用的插件
-
nodemon 能够监听项目文件的变动,当代码被修改后,nodemon 会自动帮我们重启项目,极大方便了开发和调试
npm i nodemon -g