nodejs篇 express 中间件详解
Posted 可缺不可滥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了nodejs篇 express 中间件详解相关的知识,希望对你有一定的参考价值。
文章目录
前言
上一篇文章中,简单介绍了express.js的使用,nodejs篇 express(1),其中提到了express中间件的使用。其实,在项目开发的过程中,使用express.js搭建的服务器,中间件的作用无处不在。
不同的应用场景和不同的调用方式,中间件可以分为以下几个类别:应用程序级别的中间件、路由级别的中间件、错误处理中间件、内置中间件、第三方中间件。学完之后呢,你就会对express中间件的应用得心应手。
应用程序级别的中间件
全局中间件
这类中间件的作用范围包含整个服务器的所有接口,不关心请求的具体路由,也不关心请求的方法是什么,只要是请求的服务器地址和端口号没有错,都会执行的中间件函数。
示例
var express = require("express");
var APP = express();
var PORT = 3000;
function getOriginalUrl()
return function (req, res, next)
console.log(req.originalUrl);
next();
APP.use(getOriginalUrl());
APP.post("/api", function (req, res)
res.set("Content-Type", "application/json");
res.status("200");
res.json( code: 200, data: "请求成功了" );
);
APP.get("/user/:id", function (req, res)
res.set("Content-Type", "application/json");
res.status("200");
res.json( code: 200, data: "请求成功了" );
);
APP.listen(PORT, function ()
console.log(`server runing at $PORT`);
);
如上面的代码所示,无论客户端请求api还是user/:id,都会调用getOriginalUrl方法,将请求的路由打印出来。
限定请求路径的中间件
针对特定的符合某一规则的路径,进行的函数封装处理。
var express = require("express");
var APP = express();
var PORT = 3000;
function getParams()
return function (req, res, next)
console.log(`动态路由`, req.params);
next();
;
// 只针对路径是/user/:id的中间件
APP.use("/user/:id", getParams());
APP.get("/user/:id", function (req, res)
res.status("200");
res.json( code: 200, data: "请求成功了" );
);
APP.listen(PORT, function ()
console.log(`server runing at $PORT`);
);
上述示例是只针对路径是/user/:id的中间件,当然use函数第一个参数不仅可以传低一个字符串,还可以传递一个正则,只要符合要求就会执行中间件。
限定请求方法和请求路径的中间件
这种是最常用的一种中间件使用方式
var express = require("express");
var app = express();
var port = 3000;
// express.json 就是中间件,用来处理客户端发送json数据在body中接收
app.post("/api", express.json(), function (req, res)
console.log(req.body)
res.set("Content-Type", "application/json");
res.status("200");
res.json( code: 200, data: "请求成功了" );
);
app.listen(port, function ()
console.log("server runing at 3000");
);
多个处理中间件
上面介绍的全局中间件或者是限定请求路径的中间件,或者是限定请求路径和请求方法的中间件,都可以一次性传入多个中间件。这些中间件在next() 执行后,就能够依次进行链式调用。
var express = require("express");
var APP = express();
var PORT = 3000;
function getOriginalUrl()
return function (req, res, next)
console.log(req.originalUrl, req.body);
next();
;
function setContentType(type)
return function(req,res,next)
res.set("Content-Type", type);
next()
// 全局使用多个中间件示例
APP.use(express.json(), getOriginalUrl(), setContentType("application/json"));
// 限定路径使用多个中间件示例
APP.use("/user/:id", express.json(), getOriginalUrl(), setContentType("application/json"));
// 限定路径和方法使用多个中间件示例
APP.get("/user/:id",express.json(), getOriginalUrl(), setContentType("application/json"), function (req, res)
res.status("200");
res.json( code: 200, data: "请求成功了" );
);
APP.listen(PORT, function ()
console.log(`server runing at $PORT`);
);
感觉上面的写法还是有些麻烦,我们可以简化下
var express = require("express");
var APP = express();
var PORT = 3000;
function getOriginalUrl()
return function (req, res, next)
console.log(req.originalUrl, req.body);
next();
;
function setContentType(type)
return function(req,res,next)
res.set("Content-Type", type);
next()
var middlewares = [getOriginalUrl(), setContentType("application/json"), express.json()]
// 全局使用多个中间件示例
APP.use(middlewares);
// 限定路径使用多个中间件示例
APP.use("/user/:id", middlewares);
// 限定路径和方法使用多个中间件示例
APP.get("/user/:id", middlewares, function (req, res)
res.status("200");
res.json( code: 200, data: "请求成功了" );
);
APP.listen(PORT, function ()
console.log(`server runing at $PORT`);
);
如果多个中间件,在某些情况下,我只想执行前两个中间件,不想执行第三个中间件,如何处理?
function getOriginalUrl()
return function (req, res, next)
console.log(req.originalUrl, req.body);
next();
;
function setContentType(type)
return function (req, res, next)
res.set("Content-Type", type);
// get请求时不接收前端传递过来的body参数,所以不需要处理客户端放在body中的json数据,也就是不需要express.json()
if (req.method === "GET")
// 将会结束本次app.use的调用,跳过express.json()
next("route");
next();
;
var middlewares = [
getOriginalUrl(),
setContentType("application/json"),
express.json(),
];
APP.use(middlewares);
路由级别的中间件
新建一个router.js,代码如下
var express = require("express");
// 创建路由实例
const router = express.Router();
// 配置路由
router.get("/user/:id", function (req, res)
res.status("200");
res.json( code: 200, data: "请求成功了" );
);
router.delete("/user/:id", function (req, res)
res.status("200");
res.json( code: 200, data: "请求成功了" );
);
router.post("/user", function (req, res)
res.status("200");
res.json( code: 200, data: "请求成功了" );
);
// 导出路由
module.exports = router;
在index.js中引入router,并绑定
var express = require("express");
var APP = express();
var PORT = 3000;
var router = require('./router');
function getParams()
return function (req, res, next)
console.log(`动态路由`, req.params);
next();
;
APP.use("/user/:id", getParams());
// 挂载路由
APP.use(router)
APP.listen(PORT, function ()
console.log(`server runing at $PORT`);
);
当然,如果一系列全是user开头的路径,我们可以适当改造以下
router.js中
var express = require("express");
// 创建路由实例
const router = express.Router();
// 配置路由
router.get("/:id", function (req, res)
res.status("200");
res.json( code: 200, data: "请求成功了" );
);
router.delete("/:id", function (req, res)
res.status("200");
res.json( code: 200, data: "请求成功了" );
);
router.post("/", function (req, res)
res.status("200");
res.json( code: 200, data: "请求成功了" );
);
// 导出路由
module.exports = router;
index.js中
var express = require("express");
var APP = express();
var PORT = 3000;
var router = require('./router');
function getParams()
return function (req, res, next)
console.log(`动态路由`, req.params);
next();
;
APP.use("/user/:id", getParams());
// 挂载路由
APP.use("/user", router);
APP.listen(PORT, function ()
console.log(`server runing at $PORT`);
);
改造完成的效果跟之前是一样的
错误处理中间件
var express = require("express");
var APP = express();
var PORT = 3000;
APP.delete("/user/:id", function (req, res, next)
if (req.params.id === "0")
next(
message: "该用户不存在"
);
res.status("200");
res.json( code: 200, data: "请求成功了" );
);
// 错误处理中间件,四个参数的函数,会被express认为是错误处理中间件
// 调用的位置,一般是在所有接口的后面,这样就能够拦截前面所有路径抛出的异常
// error与后面三个参数不同,是任意的,与之前next(errprParams) 有关
APP.use(function (error, req, res, next)
console.log("出错了", error.message);
res.status("500");
res.json(
message: error.message,
nodejs篇 express
文章目录
-
前言
express作为nodejs必学的模块之一,从这篇文章开始,介绍express一些基础内容,express的安装,restful接口规范,express的接口开发,express的跨域处理,express的中间件使用,请求信息req常见处理,请求头res常见处理等。为接下来真正的项目框架下开发一个express服务器做准备。
express介绍
express是在nodejs内置模块http的基础上开发,也就是说http模块有的api,express全都有,并且它们的用法也很类似。
express.js的优点在于,它封装了一些常用的,接口处理方法,更有利于中间件的扩展,让接口的开发更加规范合理等。
安装
express不是nodejs的内置模块,属于第三方开源模块,想要使用需要下载安装。
将来要部署到服务器,在开发环境和生产环境都需要使用,输入命令行
npm install express --save 或者 yarn add express
在开发过程中,会发现,我们一直在编写服务端的代码,每次修改后,都需要关掉原来的服务器,重启 node express.js
才能生效。
为此,再安装一个辅助npm包nodemon
,nodemon能自动监听文件的更新,并自动重启。
npm install -g nodemon 或者 yarn global add nodemon
安装好了之后,我们重启一下服务器,就再也不需要每次更改代码后都要重启了
nodemon express.js
RESTful接口规范
既然要开发服务器,我们就要遵循接口开发规范,这里简单介绍RESTful接口设计规范。
- 尽量使用
https
协议,如果条件不支持,就只能http
协议 - 应该尽量将所有的api都放在专有域名之下,比如
https://api.dengxi.com
,当然,如果你的接口比较简单,业务也不复杂,你就可以 主域名 + '/api'
,比如网站的域名为http://dxyx-together.cn
,那所有的api都放在http://dxyx-together.cn/api/xxx
,后面的xxx就是api具体的path。 - 版本号,如果是专有域名
https://api.dengxi.com
,当前版本为v1,那对应的就是https://api.dengxi.com/v1
,如果不是专有域名,就将版本信息放在响应头中,这样可能不如直接放在url上直观。 - 路径名称,又称为终点endpoint,命名要求不允许出现英文的动词,而应该是名词复数。比如有一个接口返回许多用户的信息,就应该设计为
xxx/api/users
。如果返回的数据直接就是某个数据库表格的内容,那就直接以数据库表格名称命名即可。 - 常用的有五种接口
get(获取数据),post(创建数据),delete(删除数据),put(完整更新数据),patch(某一数据部分更新)
,不常用的有两种(head,options)
,很多时候这几种接口类型可以混用,但按照规范,它们有属于自己的使用场景。 - 身份认证。部分接口涉及账户信息,比如常见的中后台管理系统,c端也有购物车、会员中心、钱包等场景,基于JWT的接口权限认证。
- 跨域处理,在服务端设置cors跨域处理,允许客户端跨域请求资源,特别是当接口放在专有域名下时。
- 每一个接口的每一次请求,服务器都必须给予http状态码回应和数据两个部分。
- http状态码分为五类
1xx(相关信息) 2xx(操作成功) 3xx(重定向) 4xx(客户端错误) 5xx(服务器错误)
一共有一百多种状态码,常用的也就二十多种。 - 返回的数据部分,通常是JSON对象,因此,服务器返回头需要将
Content-Type
属性设置为application/json
- 错误处理主要是需要正确使用http状态码,主要是4xx和5xx,并且返回的信息尽可能详尽,以便更快速的排查。
express的简单使用
一个最简单的服务器,仅仅只需要几行代码便可以实现。
//express.js
var express = require("express");
var app = express();
var port = 3000;
app.get("/", function (req, res)
res.send("hello world");
);
app.listen(port, function ()
console.log("server runing at 3000");
);
再输入命令行,服务器就成功启动
nodemon express.js
restful规范的五种接口类型
var express = require("express");
var app = express();
var port = 3000;
app.get("/", function (req, res)
var query = req.query
console.log(query)
res.send("hello world");
);
app.post("/", function (req, res)
res.send("post hello world");
);
app.put("/users",function(req,res)
res.send("put hello world");
)
app.delete("/users",function(req,res)
res.send("delete hello world");
)
app.patch("/users",function(req,res)
res.send("delete hello world");
)
app.listen(port, function ()
console.log("server runing at 3000");
);
请求信息req的获取
比如我们获取get请求的参数 req.query
//express.js
var express = require("express");
var app = express();
var port = 3000;
app.get("/api", function (req, res)
console.log(req.query)
res.status('200')
);
app.listen(port, function ()
console.log("server runing at 3000");
);
关于req的所有属性和方法,你可以在这里找到
http://expressjs.com/en/5x/api.html#req
中文版本的
http://expressjs.com/zh-cn/4x/api.html#req
响应信息res的设置
var express = require("express");
var app = express();
var port = 3000;
app.get("/api", function (req, res)
var query = req.query
console.log(query)
res.set('Content-Type', 'application/json')
res.status('200')
res.json(code:200,data: '请求成功了')
);
app.listen(port, function ()
console.log("server runing at 3000");
);
关于res的所有属性和方法,你可以在这里找到
http://expressjs.com/en/5x/api.html#res
中文版本
http://expressjs.com/zh-cn/4x/api.html#res
中间件的使用
express官方提供了几个比较重要的中间件
http://expressjs.com/en/5x/api.html#express
比如express.json()
,当客户端发送的数据是json数据时,req.body是取不到正常的数据的,所以,我们需要通过这个中间件处理一下才可以。
我用http模块,来请求一下我express服务器
const http = require("http");
// 请求刚刚创建的服务器
const options =
hostname: "localhost",
port: 3000,
path: "/api",
method: "post",
headers:
"Content-Type": "application/json",
,
;
const req = http.request(options, (res) =>
console.log(`状态码: $res.statusCode`);
console.log(`响应头: $JSON.stringify(res.headers)`);
res.setEncoding("utf8");
res.on("data", (chunk) =>
console.log(`响应主体: $chunk`);
);
res.on("end", () =>
console.log("响应中已无数据。");
);
);
req.write(JSON.stringify( name: "dx" )) // 发送了一个json数据
req.end();
通过app.use
来调用中间件,达到全局使用的目的
var express = require("express");
var app = express();
var port = 3000;
app.use(express.json())
app.post("/api", function (req, res)
console.log(req.body)
res.set('Content-Type', 'application/json')
res.status('200')
res.json(code:200,data: '请求成功了')
);
app.listen(port, function ()
console.log("server runing at 3000");
);
也可以在某个接口中单独使用中间件,只对这一个接口生效。
var express = require("express");
var app = express();
var port = 3000;
// app.use(express.json())
app.post("/api", express.json(), function (req, res)
// var query = req.query
console.log(req.body)
res.set('Content-Type', 'application/json')
res.status('200')
res.json(code:200,data: '请求成功了')
);
app.listen(port, function ()
console.log("server runing at 3000");
);
自定义中间件
中间件的本质,其实就是一个函数,express的中间件函数呢,有三个参数,req,res,next
创造一个中间件,用来打印日志,让每一次客户端请求的body都能在日志中看到,用来简化之前的方案。
function (req, res, next)
console.log(req.body);
// 执行下一个中间件,必须调用,否则请求会被拦截在这里
next();
再创造一个中间件,用来满足响应,总是返回status 200 并且返回相同的json
function (req, res, next)
res.set("Content-Type", "application/json");
res.status("200");
res.json( code: 200, data: "请求成功了" );
// 执行下一个中间件,必须调用,否则请求会被拦截在这里
next();
使用这两个中间件
var express = require("express");
var app = express();
var port = 3000;
app.use(express.json());
app.use(function (req, res, next)
console.log(req.body);
next();
);
app.use(function (req, res, next)
res.set("Content-Type", "application/json");
res.status("200");
res.json( code: 200, data: "请求成功了" );
next();
);
// app.post 里面啥也没干
app.post("/api", express.json(), function (req, res)
);
app.listen(port, function ()
console.log("server runing at 3000");
);
左边是服务器接口,打印了客户端传过来的name:dx,右边是客户端请求,同样拿到了状态码200和json数据。
中间件的执行顺序就是从上往下依次执行,执行的顺序也很重要。
如果是某一个单独的接口的中间件,中间件1比中间件2先执行性。
app.post("/api", 中间件1, 中间件2, function (req, res)
);
解决跨域
一 用一种粗暴的方式,任意域名都能成功请求。
var express = require("express");
var app = express();
var port = 3000;
//设置允许跨域访问该服务.
app.all("*", function (req, res, next)
res.header("Access-Control-Allow-Origin", "*"); // *表示所有域名,你也可以指定某个特别的域名 "www.dxyx-together.cn"
res.header("Access-Control-Allow-Headers", "Content-Type");
res.header("Access-Control-Allow-Methods", "*"); // *表示所有请求方式都可以跨域,你也可以设置 比如只允许get和post "GET;POST"
res.header("Content-Type", "application/json;charset=utf-8");
next();
);
app.use(express.json());
app.use(function (req, res, next)
console.log(req.body);
next();
);
app.use(function (req, res, next)
res.set("Content-Type", "application/json");
res.status("200");
res.json( code: 200, data: "请求成功了" );
next();
);
app.post("/api", express.json(), function (req, res) );
app.listen(port, function ()
console.log("server runing at 3000");
);
二 express 的 cors跨域
cors 是 Express 的一个第三方中间件,通过安装和配置 cors 中间件,可以很方便地解决跨域问题
使用步骤分为三步
- 运行
npm install cors
安装中间件 - 使用
const cors = require('cors')
导入中间件 - 在路由之前调用
app.use(cors())
配置中间件
var express = require("express");
var cors = require('cors')
var app = express();
var port = 3000;
//设置允许跨域访问该服务.
app.use(cors())
app.use(express.json());
app.use(function (req, res, next)
console.log(req.body);
next();
);
app.use(function (req, res, next)
res.set("Content-Type", "application/json");
res.status("200");
res.json( code: 200, data: "请求成功了" );
next();
);
app.post("/api", express.json(), function (req, res) );
app.listen(port, function ()
console.log("server runing at 3000");
);
cors的更多使用方式,详见cors插件官方介绍
https://www.npmjs.com/package/cors
nodejs相关其它内容
nodejs commonjs介绍
nodejs fs模块介绍
nodejs path模块介绍
nodejs events模块介绍
nodejs http模块介绍
nodejs net模块介绍
nodejs url模块介绍
nodejs process模块介绍
nodejs buffer模块介绍
nodejs stream 模块介绍
以上是关于nodejs篇 express 中间件详解的主要内容,如果未能解决你的问题,请参考以下文章
物联网服务NodeJs-5天学习第二天篇③ ——Express Web框架 和 中间件
Nodejs Express 4.X 中文API 4--- Router篇