Express
yuhuo2022-03-28开发库NodeJs库
一. 指南
构建服务
// server.js
const path = require("path");
const express = require("express");
const app = express();
// get请求
app.get("/get", (req, res) => {
// 设置状态码,返回html
res.status(404).send("HTML代码");
});
// post请求
app.post("/post", (req, res) => {
// 返回文件
res.sendFile(path.resolve("avatar.jpg"));
});
// put请求
app.put("/put", (req, res) => {
// 返回json
res.json({params: request.params});
});
// delete请求
app.delete("/delete", (req, res) => {
// 渲染html模板并返回
res.render("example/get.hbs", { name: "张三" });
});
// 所有请求类型
app.all(/.*all$/, (req, res) => {
// 设置响应头
res.header('Access-Control-Allow-Origin', '*');
});
// 开启服务
app.listen(3000, () => {
console.log(`Example app listening on port 3000`);
});
全局中间件
const express = require("express");
const app = express();
// 全局中间件
app.use((req, res, next) => {
console.log("全局路由中间件");
next();
});
// 根据路径匹配请求,请求类型不限(似乎跟app.all()一样)
app.use('/all', (req, res) => {
res.send("HTML代码");
});
// 设置静态资源目录
// 通过 http://localhost:3000/a.jpg 直接访问 ./public/a.jpg
app.use(express.static('./public'));
// 可以在最后匹配任意路径*,处理404
app.use('*', (req, res) => {
res.status(404).send("404啦!");
});
// 全局错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send("500啦!");
});
说明
express 服务由各种中间件组成,包括 app.get()
,app.post()
等方法。当请求到达时,会严格按照中间件的注册顺序依次匹配,因此顺序也很重要。比如以下情况:
- 全局中间件放在后面,可能前面的中间件匹配完就直接返回了,导致没有执行;
- 全局错误中间件放在前面,当发送错误时往后匹配已经匹配不到了;
- 匹配任意路径*的中间件放在前面,并直接返回,导致其后面的所有中间件都不会执行;
路由中间件
// 创建路由
const router = express.Router();
// 路由全局中间件
router.use((req, res, next) => {
console.log("路由组中间件");
next();
});
// 单路由中间件,语法同app,访问时需要加路由前缀,如:/animal/bird
router.get("/bird", (req, res) => {
res.send("小鸟");
});
router.get(
"/bird/:id",
(req, res, next) => {
console.log("单路由中间件");
next();
},
(req, res) => {
res.send("小鸟");
}
);
// 添加路由中间件
app.use('/animal', router);
body中间件
解析请求中的body
const express = require("express");
const cookieParser = require("body-parser");
const app = express();
// 解析 contentType=text/plain 的请求体(文本字符串)
app.use(bodyParser.text());
// 解析 contentType=application/json 的请求体(json字符串,如 {"a":1,"b":2})
app.use(bodyParser.json());
// 解析 contentType=application/x-www-form-urlencoded 的请求体(url字符串,如 a=1&b=2)
app.use(bodyParser.urlencoded());
app.post("/post", (request, response) => {
// 获取body
console.log(request.body)
});
cookie中间件
解析请求中的cookie
const express = require("express");
const cookieParser = require("cookie-parser");
const app = express();
// 解析出请求中的cookie
app.use(cookieParser());
app.get("/get", (request, response) => {
// 获取cookie
console.log(request.cookies["name"])
});
文件上传
const express = require("express");
const path = require("path");
const fs = require("fs");
const uuid = require("uuid");
const Multer = require("multer");
const bodyParser = require("body-parser");
const app = express();
const publicPath = __dirname.replace(/\\/g, "/");
const uploadPath = `${publicPath}/upload`;
const uploadUrl = "http://localhost:3000/upload";
// 注册bodyParser中间件,解析request.body
app.use(bodyParser.json());
// 跨域设置
app.use("*", (request, response, next) => {
response.header("Access-Control-Allow-Origin", "*");
response.header("Access-Control-Allow-Headers", "content-type");
next();
});
// 自动保存上传文件
const multer = Multer({
storage: Multer.diskStorage({
// 存放路径
destination: "D:/uploads/",
// 自定义文件名
filename: function (req, file, cb) {
cb(null, file.fieldname + "-" + uuid.v4() + path.extname(file.originalname));
},
}),
});
// 上传单头像
app.post("/uploadAvatar", multer.single("avatar"), (request, response) => {
response.json({ file: request.file, body: request.body });
});
// 上传多照片
app.post("/uploadPhoto", multer.array("photo"), (request, response) => {
response.json({ files: request.files, body: request.body });
});
// 上传所有
const fields = multer.fields([{ name: "avatar" }, { name: "photo" }]);
app.post("/uploadAll", fields, (request, response) => {
response.json({ files: request.files, body: request.body });
});
// 上传切片接口
app.post("/uploadChunk", Multer().single("chunkFile"), (request, response) => {
const { chunkName } = request.body;
const hash = chunkName.substring(0, chunkName.indexOf("_"));
// 切片的保存目录
const chunkPath = `${uploadPath}/${hash}`;
!fs.existsSync(chunkPath) ? fs.mkdirSync(chunkPath) : null;
// 手动保存切片
fs.writeFileSync(`${chunkPath}/${chunkName}`, request.file.buffer);
response.json({ status: 200 });
});
// 静态资源目录
app.use(express.static(publicPath));
app.listen(3000, () => {
console.log(`Example app listening on port 3000`);
});
运行
单次运行
node server.js
监听重启
安装 nodemon
npm install nodemon
配置通过 nodemon 运行脚本
// package.json
{
"scripts": {
"server": "nodemon server.js",
},
}
启动 nodemon
npm run server
二. 对象
Request
属性
属性 | 类型 | 描述 |
---|---|---|
path | string | 路径(/get) |
protocol | string | 协议(http) |
hostname | string | 主机名(localhost) |
params | object | 路径参数对象 |
query | object | 查询参数对象 |
cookies | string | cookies(需要经过 cookieParser 中间件解析) |
body | string | 请求体 |
ip | string | IP 地址 |
方法
方法 | 描述 |
---|---|
get(key: string): string | 返回指定的HTTP请求报头字段(不区分大小写) |
accepts(): string[] | 返回 accept 数组 |
Response
方法
方法 | 描述 |
---|---|
status(code: number): Response | 设定状态码,可以链式调用 |
send(html: string) | 返回HTML代码 |
sendFile(filePath: string) | 返回文件(文件路径要绝对路径) |
json(data: Object) | 返回Json对象 |
render(view: string, options: object|undefined, callback?: ((err: Error, html: string) => void)) | 渲染并返回HTML代码(示例见:HandleBars) |
header(name: string, value: string |number |string[]): Response | 设置响应头 |
setHeader(name: string, value: string |number |string[]): Response | 设置响应头 |
getHeader(name: string): string | number | string[] | undefined | 获取响应头 |
getHeaders(): Object | 获取所有响应头 |
cookie(name: string, val: string, options: CookieOptions) | 设置cookie |
CookieOptions 选项:
CookieOptions {
domain: string;
path: string; // 默认 "/"
maxAge: number; // 毫秒
expires: Date;
secure: boolean;
httpOnly: boolean;
sameSite: "strict"|"lax"|"none";
}