image-20241130012324703

Use api Route for Requests

api.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
|--------------------------------------------------------------------------
| api.js -- server routes
|--------------------------------------------------------------------------
|
| This file defines the routes for your server.
|
*/

const express = require("express");
// TODO-1 add router
const router = express.Router();

// TODO-5 migrate api/test endpoint from server.js
router.get("/test", (req, res) => {
res.send({ message: "Wow I made my first API!" });
});

// TODO-2 export router
module.exports = router;

server.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// import libraries needed for the webserver to work!
const express = require("express"); // backend framework for our node server.
const path = require("path"); // provide utilities for working with file and directory paths

// TODO-3 import the router from our API file
const api = require("./api.js");

// create a new express server
const app = express();

// allow us to make post requests
app.use(express.json());

// TODO-4 connect API routes from api.js
app.use("/api", api);

// TODO-5 migrate endpoint to api.js
app.get("/api/test", (req, res) => {
res.send({ message: "Wow I made my first API!" });
});

在代码中,app.use("/api", api) 的作用是将从 api.js 文件中导入的 路由模块 挂载到 /api 路径下,使得该模块中的所有路由都可以通过 /api 的路径前缀访问。以下是详细的解释:


app.use() 的作用

  • app.use() 是 Express 提供的方法,用于注册中间件或路由模块。
    • 中间件:对请求进行预处理(如解析 JSON 数据、身份验证等)。
    • 路由模块:定义多个路由(如 GET、POST)来处理不同的路径。
  • 在本例中,app.use("/api", api) 注册的是一个路由模块(api),并将其挂载到 /api 路径下。

app.use("/api", api) 的作用

  • 挂载路由模块到 /api 路径

    • 这里的 "/api" 是路径前缀,表示 api 中定义的所有路由都会加上这个前缀。
  • 路径的拼接

    • 如果 api.js 中定义了 /test 路由,那么访问完整路径为:

      • /api/test
    • 如果定义了 /submit 路由,那么访问完整路径为:

      • /api/submit

运行逻辑

结合 api.js 的例子,服务器处理流程如下:

GET 请求 /api/test

  • 客户端访问:http://localhost:3000/api/test
  • 执行流程:
    1. 请求匹配 app.use("/api", api)
    2. 进入 api.js 模块的路由中查找路径为 /test 的路由。
    3. 找到 router.get("/test", ...),执行其回调函数。
    4. 返回响应:{ message: "This is a test route" }

更复杂的路由管理

使用 app.use() 挂载路由模块,可以让代码更清晰和模块化,特别是对于大型项目。

示例:多个模块的路由管理

1
2
3
4
5
const users = require("./routes/users"); // 用户相关路由
const posts = require("./routes/posts"); // 帖子相关路由

app.use("/api/users", users); // 挂载用户模块
app.use("/api/posts", posts); // 挂载帖子模块
  • 如果 users.js 定义了 /profile 路由,则完整路径为 /api/users/profile
  • 如果 posts.js 定义了 /create 路由,则完整路径为 /api/posts/create

路由

image-20241130135136270

req

req是传入的请求

  • req.query
  • req.body
  • req.params
  • Custom keys (ie. req.user)

image-20241130135425855

image-20241130135434692

res

res是你服务器的响应

  • res.status (<status code>)
  • res.send(<object>)

GET路由

1
2
3
4
5
6
7
8
9
10
11
12
13
router.get("/test", (req, res) => {
res.send({ message: "Wow I made my first API! In its own file!" });
});

router.get("/stories", (req, res) => {
// send back all of the stories!
res.send(data.stories);
});

router.get("/comment", (req, res) => {
const filteredComments = data.comments.filter((comment) => comment.parent == req.query.parent);
res.send(filteredComments);
});

POST路由

当我们写好GET路由后,我们可以提交下新的story,打开控制板会发现这样的请求

image-20241130140034623

image-20241130140044038

他提交了content: "1"失败,因为我们还没开始写post路由

我们在写post路由的时候可以用req.body.content把用户请求的内容添加进来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
router.post("/story", (req, res) => {
const newStory = {
_id: data.stories.length,
creator_name: myName,
content: req.body.content,
};

data.stories.push(newStory);
res.send(newStory);
});

router.post("/comment", (req, res) => {
const newComment = {
_id: data.comments.length,
creator_name: myName,
parent: req.body.parent,
content: req.body.content,
};

data.comments.push(newComment);
res.send(newComment);
});

catch all /api 路由

1
2
3
4
router.all("*", (req, res) => {
console.log(`API Route not found: ${req.method} ${req.url}`);
res.status(404).send({ message: "API Route not found" });
});

这段代码需要写在其他路由的下面,不然所有路由都会被它截取

总结

HTTP 请求和响应的基本流程

  • 客户端发送 HTTP 请求(如 GET 请求)到服务器,指定目标资源(如 localhost:3000/stories)。
  • 服务器接收到请求后处理逻辑,提取所需数据。
  • 服务器返回 HTTP 响应,包含状态码(如 200 表示成功)和数据(如 JSON 格式的故事列表)。
  • 客户端接收响应,并将获取的数据(如故事列表)渲染到页面上供用户查看。

HTTP 请求结构

  • 包括方法(GET、POST 等)、目标 URL 和可选的请求体。
  • 示例:GET 请求中请求体为空,仅通过 URL 和查询参数指定所需数据。

HTTP 响应结构

  • 包括状态码和响应体。状态码如 200 表示成功,响应体通常为 JSON 格式数据(如故事的数组,每个故事是一个对象)。

代码实现的关联

  • 前端:使用 fetch 或类似工具发送 GET 请求,处理 Promise,接收服务器响应并渲染数据。
  • 后端:定义路由(如 router.get('/stories')),监听客户端请求,获取所需数据并通过 res.send() 返回响应。

四个核心步骤

  1. 客户端发送请求(如调用 getSLStories())。
  2. 服务器接收请求并进行处理。
  3. 服务器发送响应,包含请求数据。
  4. 客户端渲染数据,将其显示在前端页面。

查询参数的使用

  • 在某些情况下,需要通过查询参数向服务器传递额外信息(如获取特定评论),以实现更加细粒度的数据获取。