一、路由(Routing)
1. 什么是路由?
路由(Routing)本质是 "根据请求条件,映射到对应处理逻辑"的机制。
-
前端路由:根据 URL 变化,渲染对应的页面/组件(不刷新页面)。
-
后端路由:根据 HTTP 方法(GET/POST 等)和 URL 路径,分发到对应的控制器/函数处理。
2. 前端路由(SPA 核心)
常见模式:
-
Hash 模式 (
#号后面的变化,不会触发页面刷新,兼容性好) -
History 模式 (利用
history.pushState,URL 更优雅,需服务端配合)
原生 JS 实现简单路由(Hash 模式)
html
<!DOCTYPE html>
<html>
<body>
<nav>
<a href="#/home">首页</a>
<a href="#/about">关于</a>
</nav>
<div id="app"></div>
<script>
function render(path) {
const app = document.getElementById('app');
if (path === '/home') app.innerHTML = '<h1>🏠 首页</h1>';
else if (path === '/about') app.innerHTML = '<h1>📄 关于我们</h1>';
else app.innerHTML = '<h1>404</h1>';
}
// 监听 hash 变化
window.addEventListener('hashchange', () => {
const path = window.location.hash.slice(1) || '/home';
render(path);
});
// 首次加载执行
window.addEventListener('DOMContentLoaded', () => {
const path = window.location.hash.slice(1) || '/home';
render(path);
});
</script>
</body>
</html>
3. 后端路由(以 Express.js 为例)
后端路由收到请求后,执行数据库查询、业务逻辑,最终返回 JSON/HTML。
javascript
const express = require('express');
const app = express();
// 路由:GET /users
app.get('/users', (req, res) => {
res.json([{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]);
});
// 路由:POST /users
app.post('/users', (req, res) => {
// 假设保存新用户
res.status(201).json({ message: '用户创建成功' });
});
// 动态路由参数 :id
app.get('/users/:id', (req, res) => {
const userId = req.params.id;
res.json({ id: userId, name: `User ${userId}` });
});
// 启动服务
app.listen(3000, () => console.log('服务运行在 http://localhost:3000'));
二、接口(API / Interface)
1. 什么是接口?
接口是 前后端交互的契约。它定义了:
-
请求方式(GET/POST/PUT/DELETE)
-
请求路径(如
/api/orders) -
请求参数(Query、Body、Header)
-
响应格式(状态码、数据结构)
2. RESTful 风格接口(最主流)
REST 强调资源(Resource),用 HTTP 方法代表操作:
| 方法 | 路径 | 含义 |
|---|---|---|
| GET | /books | 获取所有书籍 |
| GET | /books/:id | 获取某本书 |
| POST | /books | 新增一本书 |
| PUT | /books/:id | 完整更新某本书 |
| DELETE | /books/:id | 删除某本书 |
Node.js + Express 实现 RESTful 接口
javascript
const express = require('express');
const app = express();
app.use(express.json()); // 解析 JSON 请求体
let books = [
{ id: 1, title: '红楼梦', author: '曹雪芹' },
{ id: 2, title: '西游记', author: '吴承恩' }
];
// 获取所有书籍
app.get('/api/books', (req, res) => {
res.json(books);
});
// 获取单本书籍
app.get('/api/books/:id', (req, res) => {
const book = books.find(b => b.id === parseInt(req.params.id));
if (!book) return res.status(404).json({ error: '书籍不存在' });
res.json(book);
});
// 新增书籍
app.post('/api/books', (req, res) => {
const newBook = { id: books.length + 1, ...req.body };
books.push(newBook);
res.status(201).json(newBook);
});
// 更新书籍(全量更新)
app.put('/api/books/:id', (req, res) => {
const index = books.findIndex(b => b.id === parseInt(req.params.id));
if (index === -1) return res.status(404).json({ error: '书籍不存在' });
books[index] = { id: parseInt(req.params.id), ...req.body };
res.json(books[index]);
});
// 删除书籍
app.delete('/api/books/:id', (req, res) => {
const index = books.findIndex(b => b.id === parseInt(req.params.id));
if (index === -1) return res.status(404).json({ error: '书籍不存在' });
books.splice(index, 1);
res.status(204).send(); // 无内容返回
});
app.listen(3000);
3. GraphQL 接口(灵活查询)
GraphQL 允许客户端精确指定所需字段,减少过取或欠取。
简单 GraphQL 示例(Apollo Server)
javascript
const { ApolloServer, gql } = require('apollo-server');
// 定义类型和查询
const typeDefs = gql`
type Book {
id: ID!
title: String!
author: String!
}
type Query {
books: [Book]
book(id: ID!): Book
}
type Mutation {
addBook(title: String!, author: String!): Book
}
`;
const books = [
{ id: '1', title: '三体', author: '刘慈欣' },
{ id: '2', title: '流浪地球', author: '刘慈欣' }
];
const resolvers = {
Query: {
books: () => books,
book: (parent, args) => books.find(b => b.id === args.id)
},
Mutation: {
addBook: (parent, args) => {
const newBook = { id: String(books.length + 1), ...args };
books.push(newBook);
return newBook;
}
}
};
const server = new ApolloServer({ typeDefs, resolvers });
server.listen(4000).then(() => console.log('GraphQL 服务已启动 http://localhost:4000'));
三、路由与接口的关系与最佳实践
1. 关系
-
路由是"分发器",决定请求交给谁处理。
-
接口是"具体处理逻辑 + 数据格式规范"。
-
通常后端路由直接对应接口路径(如
/api/users)。
2. 实践中如何设计?
-
路径设计 :使用名词复数表示资源,如
/orders而不是/getOrders。 -
状态码语义化:
-
200 OK(成功)
-
201 Created(创建成功)
-
400 Bad Request(参数错误)
-
401 Unauthorized(未认证)
-
403 Forbidden(无权限)
-
404 Not Found(资源不存在)
-
500 Internal Server Error(服务器内部错误)
-
-
版本控制 :在路径中加入版本,如
/api/v1/users。
3. 前端如何调用接口?(Fetch 示例)
javascript
// GET 请求
fetch('http://localhost:3000/api/books')
.then(res => res.json())
.then(data => console.log(data));
// POST 请求
fetch('http://localhost:3000/api/books', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: '朝花夕拾', author: '鲁迅' })
})
.then(res => res.json())
.then(newBook => console.log('新增成功', newBook));
四、总结
| 概念 | 核心职责 | 常见技术/形式 |
|---|---|---|
| 前端路由 | 控制页面视图切换(SPA) | Hash/History + 组件渲染 |
| 后端路由 | 分发请求到具体控制器/函数 | Express/Koa 路由、Spring MVC |
| RESTful 接口 | 以资源为中心,用 HTTP 方法操作 | GET/POST/PUT/DELETE + JSON |
| GraphQL 接口 | 客户端按需查询,减少多次请求 | 单一端点 + 强类型 Schema |
关键一句话:
路由解决"去哪儿",接口解决"干什么"以及"怎么干"。