116181545032456974
前言
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
| 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()才会继续执行其他匹配成功的中间件
- 如果当前中间件中没有返回响应或进入下一个中间件,则请求会被挂起
中间件的类型
普通中间件
任意匹配的中间件
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; });
|
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; });
|
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
| resp.setHeader("<key>", "<value>");
|
设置响应体
写入文本内容并返回响应
写入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 2 3 4
| const morgan = require("morgan");
const writeStream = fs.createWriteStream("./access.log"); app.use(morgan("combined", { stream: writeStream }));
|
下载依赖
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 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(); } });
|
完成
参考文献
哔哩哔哩——黑马程序员