前言
先交代下背景:我大二才转到计算机,之前就会写点静态页面。最近想做个校园论坛,结果瞬间被三个问题卡住了脖子:
- 我想点击导航栏切换内容,但不想整个页面刷新(单页应用体验)。
- 我想让用户直接访问
/post/123就能看到对应帖子详情。 - 我还需要写后端接口,让前端能登录、注册、发帖。
琢磨了一圈,发现这三个问题全指向同一个东西——路由。学完之后我觉得路由真没想象中那么抽象,而且前端和后端的路由思想是通的。这篇文章就当是我的学习笔记,希望能帮到同样困惑的你。
1. 什么是路由?
想象你去酒店,前台问:“先生,您的房号是?”你说“602”,然后服务员带你到602房间。
- 房号 = 路径
- 服务员 = 路由器
- 602房间 = 处理结果
在 Web 开发里,路由就是:根据请求的 URL(以及 HTTP 方法),找到对应的处理函数,然后返回页面、数据或者 JSON。
2. 前端路由和后端路由分别干嘛?
前端路由(Vue Router / React Router)
- 场景:单页应用(SPA),页面不刷新就切换内容。
- 原理:监听 URL 变化,渲染对应的组件。
后端路由(Express / Koa)
- 场景:提供 API 接口,或者返回不同的 HTML 页面。
- 原理:服务器收到请求,匹配路径和方法,执行代码,返回响应。
这篇文章我会把前端路由带一遍(因为很常用),但重点放在 Express 后端路由上。
3. 前端路由速览(Vue Router)
这块简单过一下,但基础用法要知道。已经了解的同学可以跳过·这一段。
3.1 安装配置
npm install vue-router
src/router/index.js:
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import About from '../views/About.vue'
const routes = [
{ path: '/', component: Home },
{ path: '/about', component: About },
{ path: '/post/:id', component: () => import('../views/PostDetail.vue') }
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
3.2 跳转和获取参数
<template>
<router-link to="/">首页</router-link>
<button @click="$router.push('/post/123')">去帖子</button>
</template>
在 PostDetail.vue 里拿参数:
import { useRoute } from 'vue-router'
const route = useRoute()
const postId = route.params.id // 123
3.3 一个前端踩坑:部署后刷新404
项目部署到 Vercel 上,点击路由跳转正常,但一刷新页面就 404。
原因:Vercel 默认只认真实文件路径,不认识前端路由的虚拟路径。
解决:项目根目录加 vercel.json:
{
"rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
}
意思是所有请求都返回 index.html,剩下的交给 Vue Router。
4. 重点:后端路由(Express 实战)
下面就是这次的重头戏,也是我踩坑最多的地方。
4.1 搭一个最简单的服务器
npm init -y
npm install express cors
index.js:
const express = require('express')
const cors = require('cors')
const app = express()
const port = 3000
app.use(cors())
app.use(express.json()) // 千万别忘,后面会说
app.get('/', (req, res) => {
res.send('Hello World')
})
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`)
})
4.2 不同 HTTP 方法的路由
// 获取帖子列表
app.get('/posts', (req, res) => {
res.json([{ id: 1, title: '帖子1' }])
})
// 创建新帖子
app.post('/posts', (req, res) => {
const { title, content } = req.body
// 存数据库...
res.status(201).json({ message: '创建成功' })
})
// 更新帖子
app.put('/posts/:id', (req, res) => {
const { id } = req.params
res.send(`更新帖子 ${id}`)
})
// 删除帖子
app.delete('/posts/:id', (req, res) => {
const { id } = req.params
res.send(`删除帖子 ${id}`)
})
4.3 获取参数的三种姿势
- 路径参数:
/user/:id→req.params.id - 查询参数:
/search?keyword=vue→req.query.keyword - 请求体:POST 请求 JSON →
req.body
4.4 路由模块化(express.Router)
项目大了不能全写在一个文件里,就可以用 Router 拆分一下。
routes/user.js:
const express = require('express')
const router = express.Router()
router.post('/login', (req, res) => {
res.send('登录成功')
})
router.post('/register', (req, res) => {
res.send('注册成功')
})
module.exports = router
index.js 挂载:
const userRouter = require('./routes/user')
app.use('/user', userRouter) // 最终路径:/user/login, /user/register
4.5 后端踩坑合辑
⚠️ 坑1:req.body 一直是 undefined
前端明明发了请求,后端 console.log(req.body) 却是 undefined。
原因:忘了加 app.use(express.json()) 中间件。
解决:在路由前加上这一行。这个坑我起码踩过三次,现在写 Express 第一件事就是检查这行有没有写。
⚠️ 坑2:路由顺序写错,导致匹配混乱
比如我写了:
app.get('/user/:id', ...) // 动态路由
app.post('/user/login', ...) // 具体路由
访问 /user/login 的时候,Express 会先匹配到 /user/:id,然后把 login 当成 id 参数,导致登录逻辑根本不执行。
解决:把具体路径写在动态路径前面。
app.post('/user/login', ...) // 具体路径在前
app.get('/user/:id', ...) // 动态路径在后
5. 前后端路由的简单对比
| 维度 | 前端路由(Vue Router) | 后端路由(Express) |
|---|---|---|
| 运行环境 | 浏览器 | 服务器 |
| 触发方式 | 点击链接、router.push | HTTP 请求 |
| 参数传递 | params, query | params, query, body |
| 响应内容 | 渲染组件 | JSON 或 HTML |
| 拦截机制 | beforeEach 守卫 | 中间件 app.use() |
虽然环境不同,但核心思想完全一样:路径 → 处理函数。理解了一个,另一个上手就很快。
6. 最后想说的
路由这玩意儿,光看概念会觉得有点难以理解,真上手写一遍就明白了。我写这篇笔记的时候,已经把我踩过的坑都尽量标出来了,希望你不用再掉进去。
现在我的校园论坛项目还在修修补补,但起码路由这部分心里有底了。如果你也是初学者,建议把上面的代码自己敲一遍,尤其是 Express 那几段。
对了,你刚学路由的时候,踩过哪些想摔键盘的坑?评论区分享一下,让我知道我不是一个人 😂
Happy Coding!