https://www.expressjs.com.cn/
npm i express
安装接口测试工具Postman
https://www.postman.com/downloads/
创建app.js文件
const express = require("express"); const app = express(); const port = 3000 // 默认3000 app.get("/", (req, res) => { res.send("Hello World"); }); app.listen(3000, () => { console.log(`Server running at http://localhost:${port}/`); });
运行app.js
打开网页
可以使用nodemon启动程序
这样可以检测文件变化,自动更新程序
Postman接口测试
路由是指确定应用程序响应客户端对特定端点的请求,该特定端点是URI和特定HTTP请求方法(GET/POST等)
每个路由可以具有一个或多个处理程序函数,这些函数在匹配该路由时执行
路由定义采用以下结构
app.METHOD(path, handle)
app
Express实例METHOD
小写的HTTP请求方法path
服务器上的路由路径handle
当路由匹配时执行的处理函数更多路由相关
https://www.expressjs.com.cn/guide/routing.html
app.get('/', (req, res) => { res.send('Hello World') })
app.post('/', (req, res) => { res.send('Got a POST request') })
app.put("/user", (req, res) => { res.send("Got a POST request at /user"); });
app.delete("/user", (req, res) => { res.send("Got a DELETE request at /user"); });
Express 应用使用路由回调函数的参数 request
和 response
对象来处理请求和响应的数据
app.get('/', (request, response)=>{ // ... })
Express不对Node.js已有的特性进行二次抽象,只是在它之上拓展了web应用所需的基本功能
http.IncomingMessage
http.ServerResponse
Express拓展了HTTP模块中的请求和响应对象
API
Node.js https://nodejs.org/dist/latest-v14.x/docs/api/http.html
Express https://www.expressjs.com.cn/4x/api.html#req
request
对象代表HTTP请求,并具有请求查询字符串,参数,正文,HTTP标头等属性
app.get("/", (request, res) => { console.log("request.url:", request.url); console.log("request.method:", request.method); console.log("request.headers:", request.headers); console.log('请求参数:', request.query) res.send("Hello World"); });
postman发送请求
控制台输出
Node.js https://nodejs.org/dist/latest-v14.x/docs/api/http.html
Express https://www.expressjs.com.cn/4x/api.html#res
app.get("/", (request, response) => { // 设置响应状态码 // response.statusCode = 201 // response.write('a') // response.write('b') // response.write('c') // 结束响应 // response.end() // response.end('efg') // response.send("Hello World"); // response.send({ // name: 'yk' // }) response.cookie('yk', 'kk') response.status(201).send('OK') });
通过该案例创建一个简单的CRUD接口服务,从而掌握Express的基本用法
需求:实现对任务清单的CRUD接口服务
首先创建一个文件db.json用来存储数据
{ "todos": [ { "id": 1, "title": "吃饭" }, { "id": 2, "title": "睡觉" }, { "id": 3, "title": "写代码" } ] }
app.get("/todos", (req, res) => { fs.readFile("./db.json", "utf8", (err, data) => { if (err) { return res.status(500).json({ error: err.message, }); } const db = JSON.parse(data); res.status(200).json(db.todos); }); });
测试
app.get("/todos/:id", (req, res) => { fs.readFile("./db.json", "utf8", (err, data) => { if (err) { return res.status(500).json({ error: err.message, }); } const db = JSON.parse(data); // console.log(typeof req.params.id) // string const todo = db.todos.find((todo) => todo.id === +req.params.id); if (!todo) { return res.status(404).end(); } res.status(200).json(todo); }); });
测试
创建db.js
const fs = require("fs"); const { promisify } = require("util"); const path = require("path"); const readFile = promisify(fs.readFile); const dbPath = path.join(__dirname, "./db.json"); exports.getDb = async () => { const data = await readFile(dbPath, "utf8"); return JSON.parse(data); };
优化后的GET请求
const { getDb } = require("./db"); app.get("/todos", async (req, res) => { try { const db = await getDb(); res.status(200).json(db.todos); } catch (err) { res.status(500).json({ error: err.message, }); } }); app.get("/todos/:id", async (req, res) => { try { const db = await getDb(); const todo = db.todos.find((todo) => todo.id === +req.params.id); if (!todo) { return res.status(404).end(); } res.status(200).json(todo); } catch (err) { res.status(500).json({ error: err.message, }); } });
在db.js中
封装保存文件的方法saveDb
const writeFile = promisify(fs.writeFile); exports.saveDb = async (db) => { const data = JSON.stringify(db, null, " "); await writeFile(dbPath,data); };
在app.js中
【中间件】
配置解析表单请求体:application/json
app.use(express.json());
配置解析表单请求体:applicatioin/x-www-form-urlencoded
app.use(express.urlencoded());
完整代码
app.post("/todos", async (req, res) => { try { // 1. 获取客户端请求体参数 const todo = req.body; // 2. 数据验证 if (!todo.title) { return res.status(422).json({ error: "The filed title is required.", }); } // 3. 数据验证通过,把数据存储到db中 const db = await getDb(); const lastTodo = db.todos[db.todos.length - 1]; todo.id = lastTodo ? lastTodo.id + 1 : 1; db.todos.push(todo); await saveDb(db); // 4. 发送响应 res.status(201).json(todo); } catch (err) { res.status(500).json({ error: err.message, }); } });
测试
db.json文件更新
app.patch("/todos/:id", async (req, res) => { try { // 1. 获取表单数据 const todo = req.body; // 2. 查找到要修改的任务项 const db = await getDb(); const result = db.todos.find((todo) => todo.id === +req.params.id); if (!result) { return res.status(404).end(); } // 3. 合并对象 Object.assign(result, todo); await saveDb(db); // 4. 发送响应 res.status(200).json(result); } catch (err) { res.status(500).json({ error: err.message, }); } });
app.delete("/todos/:id", async (req, res) => { try { const db = await getDb(); const index = db.todos.findIndex((todo) => todo.id === +req.params.id); if (index === -1) { return res.status(404).end(); } db.todos.splice(index, 1); await saveDb(db); res.status(204).end(); } catch (err) { res.status(500).json({ error: err.message, }); } });
测试