Express起步 - 路由基础 - 请求对象request - 响应对象response - 增删改查API案例

Posted YK菌

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Express起步 - 路由基础 - 请求对象request - 响应对象response - 增删改查API案例相关的知识,希望对你有一定的参考价值。

1. 起步

2021 最新最全 Express 教程(基础+实战+原理),B 站最好,没有之一

1.1 文档

https://www.expressjs.com.cn/

在这里插入图片描述

1.2 安装

npm i express

在这里插入图片描述
安装接口测试工具Postman
https://www.postman.com/downloads/

1.3 Hello World

创建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接口测试
在这里插入图片描述

2. 路由基础

路由是指确定应用程序响应客户端对特定端点的请求,该特定端点是URI和特定HTTP请求方法(GET/POST等)
每个路由可以具有一个或多个处理程序函数,这些函数在匹配该路由时执行

路由定义采用以下结构

app.METHOD(path, handle)
  • app Express实例
  • METHOD 小写的HTTP请求方法
  • path 服务器上的路由路径
  • handle 当路由匹配时执行的处理函数

更多路由相关
https://www.expressjs.com.cn/guide/routing.html

demo

  1. 在根路径响应 ‘Hello World’
app.get('/', (req, res) => {
  res.send('Hello World')
})

在这里插入图片描述

  1. 在根路径响应POST请求
app.post('/', (req, res) => {
  res.send('Got a POST request')
})

在这里插入图片描述

  1. 响应对/user路径的PUT请求
app.put("/user", (req, res) => {
  res.send("Got a POST request at /user");
});

在这里插入图片描述

  1. 响应对/user路径的DELETE 请求
app.delete("/user", (req, res) => {
  res.send("Got a DELETE request at /user");
});

在这里插入图片描述

3. 请求和响应

Express 应用使用路由回调函数的参数 requestresponse 对象来处理请求响应的数据

app.get('/', (request, response)=>{
	// ...
})

Express不对Node.js已有的特性进行二次抽象,只是在它之上拓展了web应用所需的基本功能

  • 内部使用的还是http模块
  • 请求对象继承自 http.IncomingMessage
  • 响应对象继承自 http.ServerResponse

Express拓展了HTTP模块中的请求和响应对象

3.1 请求对象 request

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发送请求
在这里插入图片描述

控制台输出
在这里插入图片描述

3.2 响应对象 response

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')
});

在这里插入图片描述

3.3 案例

通过该案例创建一个简单的CRUD接口服务,从而掌握Express的基本用法

需求:实现对任务清单的CRUD接口服务

  • 查询任务列表
    • GET /todos
  • 根据ID查询单个任务
    • GET /todos/:id
  • 添加任务
    • POST /todos
  • 修改任务
    • PATCH /todos
  • 删除任务
    • DELETE /todos/:id

首先创建一个文件db.json用来存储数据

{
  "todos": [
    {
      "id": 1,
      "title": "吃饭"
    },
    {
      "id": 2,
      "title": "睡觉"
    },
    {
      "id": 3,
      "title": "写代码"
    }
  ]
}

GET 查询任务列表

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);
  });
});

测试
在这里插入图片描述

GET 根据ID查询单个任务

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,
    });
  }
});

POST添加任务

在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文件更新
在这里插入图片描述

PATCH 修改任务

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,
    });
  }
});

在这里插入图片描述
在这里插入图片描述

DELETE 删除任务

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,
    });
  }
});

测试
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4. 路由详细

路由方法

路由方法是从HTTP方法之一派生的,并附加到express该类的实例

以下代码是为GET和POST方法定义的到应用根目录的路由的示例

app.get('/', (req, res) => {
  res.send('GET request to the homeage')
})
app.post('/', (req, res) => {
  res.send('POST request to the homeage')
})

Express支持与所有HTTP请求方法相对应的方法:get,post等。
有关完整列表请见https://www.expressjs.com.cn/4x/api.html#routing-methods

还有一种特殊的路由方法,app.all()用于为所有HTTP请求方法的路径加载中间件功能。无论是使用GET, POST, PUT, DELETE还是http模块支持的任何其他HTTP请求方法,都会对路由的请求执行以下处理程序

app.all('/', (req, res) => {
  console.log("all Method");
  next();
})

路由路径

路由路径与请求方法结合,定义了可以进行请求的端点。
路由路径可以是【字符串】,【字符串模式】或【正则表达式】。
子符?+*() 是他们的正则表达式的对应的子集。
连字符-和点.由基于字符串的路径字面意义进行解释
如果需要$在路径字符串中使用美元字符,要将其转移([并括在和中])
例如/data/$book用于请求的路径字符串将为 /data/([\\s])book

Express使用path-to-regexp来匹配路由路径;有关定义路由路径的所有可能性满清参见正则表达式路径文档

Express Route Tester 尽管不支持模式匹配,但却是用于测试基本Express路由的便捷工具

查询字符串不是路由路径的一部分

基于【字符串】的路由路径示例

  1. 此路由路径会将请求匹配到根路由/
app.get('/', (req, res) => {
  res.send('root');
})
  1. 此路由路径会将请求匹配到/about
以上是关于Express起步 - 路由基础 - 请求对象request - 响应对象response - 增删改查API案例的主要内容,如果未能解决你的问题,请参考以下文章

Express基础单词

「Vue」起步 - vue-router路由与页面间导航

三Express 路由

express框架学习

Express简单使用

Express简单使用