【笔记】Express学习笔记

前言

Fast, unopinionated, minimalist web framework for Node.js(官网

通过脚手架管理Express项目

下载依赖

1
npm install -g express-generator

创建项目

1
2
3
express <project_name>
cd <project_name>
npm install

启动项目

1
node bin/www

下载依赖

1
npm install express

引入依赖

1
const express = require("express");

创建Web服务器

1
2
3
4
5
const app = express();
app.get("/", function (request, response, next) {
response.end();
});
app.listen(8080);
1
2
3
4
5
6
7
const app = express();
app.get("/", function (request, response, next) {
response.end();
});
app.listen(8080, function () {
console.log(`http://127.0.0.1:8080`);
});
1
2
3
4
5
6
7
const app = express();
app.get("/", function (request, response, next) {
response.end();
});
app.listen(8080, "0.0.0.0", function () {
console.log(`http://127.0.0.1:8080`);
});

中间件

  • Express会执行第一个匹配成功的中间件,只有调用了next()才会继续执行其他匹配成功的中间件
  • 如果当前中间件中没有返回响应进入下一个中间件,则请求会被挂起

中间件的类型

普通中间件

  • 通过无参next()可以跳转到匹配的普通中间件
任意匹配的中间件
  • 注册一个中间件
1
2
3
app.use(function (request, response, next) {
...
});
  • 注册多个中间件
1
2
3
4
5
app.use(function (request, response, next) {
...
}, function (request, response, next) {
...
});
path匹配的中间件
1
2
3
app.use("/", function (request, response, next) {
...
});
path和method匹配的中间件
1
2
3
app.get("/", function (request, response, next) {
...
});

错误处理中间件

  • 通过有参next()可以跳转到匹配的错误处理中间件
1
2
3
app.use(function (error, request, response, next) {
...
});

继续执行下一个中间件

跳转到下一个中间件

  • 后面的代码不会等到next()返回后执行,所以通常在中间件最后一行调用next()
1
2
3
4
5
6
app.use(function (request, response, next) {
...
next();
}, function (request, response, next) {
...
});

跳转到下一个错误处理中间件

1
2
3
4
5
app.use(function (request, response, next) {
next("");
}, function (error, request, response, next) {
...
});

处理请求

获取请求头

1
const key = request.headers["key"];

获取请求参数

query

1
2
3
app.get("/", function (request, response, next) {
const queryInfo = request.query;
});

body

JSON
1
2
3
4
5
app.use(express.json());

app.post("/", function (request, response, next) {
const body = request.body;
});
Form
1
2
3
4
5
app.use(express.urlencoded());

app.post("/", function (request, response, next) {
const body = request.body;
});

{ extended: false }:缺省值,使用内置的queryString模块作为解析器
{ extended: true }:不使用内置的queryString模块,而使用第三方的qs模块作为解析器

1
2
3
4
5
app.use(express.urlencoded({ extended: true }));

app.post("/", function (request, response, next) {
const body = request.body;
});
Form + JSON
  • 根据Content-Type请求头自动切换解析器
1
2
3
4
5
6
app.use(express.json());
app.use(express.urlencoded());

app.post("/", function (request, response, next) {
const body = request.body;
});

path

1
2
3
app.get("/:id", (request, response, next) => {
const id = request.params.id;
})

处理响应

设置响应行

设置响应状态码

1
response.status(200);

设置响应头

1
resp.setHeader("<key>", "<value>");

设置响应体

写入文本内容并返回响应

1
response.end("文本内容");

写入JSON并返回响应

1
response.json({});

路由

1
2
3
4
5
6
7
const router = express.Router();

router.get("/", function (request, response, next) {
...
});

app.use("/api", router);

静态资源服务器

  • 静态资源默认从根访问
1
2
3
const static = express.static("./public");

app.use(static);
  • 指定资源前缀
1
2
3
const static = express.static("./public");

app.use("/", static);

第三方中间件

日志中间件

  • 自动记录日志,并输出到文件

下载依赖

1
npm install morgan

输出日志

1
2
3
4
const morgan = require("morgan");

const writeStream = fs.createWriteStream("./access.log");
app.use(morgan("combined", { stream: writeStream }));

解析Form请求参数

  • 用于解析文件上传请求参数

下载依赖

1
npm install multer

解析Form请求参数

1
2
3
4
5
6
7
const multer = require("multer");

const formData = multer();

app.post("/", formData.any(), function (request, response, next) {
const body = request.body;
});

解析单个文件上传请求参数

{ dest: "./uploads" }:指定文件存放目录

1
2
3
4
5
6
7
const multer = require("multer");

const upload = multer({ dest: "./uploads" });

app.post("/", upload.single("key"), function (request, response, next) {
const file = request.file;
});
1
2
3
4
5
6
7
8
9
10
{
fieldname: "file",
originalname: "file.png",
encoding: "7bit",
mimetype: "image/png",
destination: "./uploads",
filename: "file.png",
path: "./uploads/file.png",
size: 1024
}
  • 自定义文件名

"./uploads":指定文件存放目录
file.originalname:原始文件名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const multer = require("multer");

const upload = multer.diskStorage({
destination: function (request, file, callback) {
callback(null, "./uploads");
},
filename: function (request, file, callback) {
callback(null, file.originalname);
}
});

app.post("/", upload.single("key"), function (request, response, next) {
const file = request.file;
});

解析多个文件上传请求参数

1
2
3
4
5
6
7
const multer = require("multer");

const upload = multer({ dest: "./uploads" });

app.post("/", upload.array("key"), function (request, response, next) {
const files = request.files;
});
1
2
3
4
5
6
7
8
9
10
11
12
[
{
fieldname: "file",
originalname: "file.png",
encoding: "7bit",
mimetype: "image/png",
destination: "./uploads",
filename: "file.png",
path: "./uploads/file.png",
size: 1024
}
]

允许跨域中间件

下载依赖

1
npm install cors

全局注册中间件

1
2
3
const cors = require("cors");

app.use(cors());

Session会话中间件

下载依赖

1
npm install express-session

全局注册中间件

secret:定义密钥
resave:是否强制保存会话数据到存储

true:无论是否修改会话数据都进行保存操作
false:只有修改会话数据时才会进行保存操作

saveUninitialized:是否保存空会话数据

true:无论是否添加会话数据都创建会话
false:只有尝试添加会话数据时才会创建会话

1
2
3
4
5
6
7
const session = require("express-session");

app.use(session({
secret: "",
resave: false,
saveUninitialized: true
}));

添加或修改会话数据

1
2
3
app.get("/", function (request, response, next) {
request.session.key = "value";
});

销毁会话数据

1
2
3
app.get("/", function (request, response, next) {
request.session.destroy();
});

JWT中间件

下载依赖

1
npm install jsonwebtoken express-jwt

签发令牌

  • 通过jsonwebtoken模块提供的sign()创建令牌
1
2
3
4
5
6
7
8
9
const jwt = require("jsonwebtoken");

const secret = "";

app.get("/", function (request, response, next) {
const token = {
token: jwt.sign({}, secret, { expiresIn: "30s" })
};
});

校验令牌

  • 通过全局注册express-jwt模块创建的中间件,实现自动校验请求携带携带的令牌
    • unless()中定义的路径,无需校验令牌,直接通过校验
    • 校验令牌成功,会将数据自动添加到request.user
    • 校验令牌失败,会报错next("UnauthorizedError")

unless():定义无需校验令牌的接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const jwt = require("express-jwt");

const secret = "";

app.use(jwt({ secret: secret }).unless({ path: [/^/login/] }));

app.use("/", function (request, response, next) {
const user = request.user;
});

app.use(function (error, request, response, next) {
if (error.name === "UnauthorizedError") {
response.status(401).send();
}
});

完成

参考文献

哔哩哔哩——黑马程序员