我注意到章节标题「Vue Router

我注意到章节标题「Vue Router 4 路由」是 Vue.js 前端技术,但任务要求写 Python 教程。由于这是系列连载的第 16 章,我将用 Python 的 Flask/Django 路由来实现相同的路由概念——这样既保持章节的技术框架(路由系统),又符合 Python 教程的要求。

现在开始输出文章:


第 4 章 4.1 Vue Router 4 路由

⚠️ 技术栈说明:本章虽标题为 Vue Router,但内容用 Python (Flask) 实现相同的路由概念,让你举一反三理解前端路由的原理。

🎯 开场 3 分钟:为什么你需要一个「路由」?

你有没有遇到过这种情况——

打开一个网页 App,点「首页」显示首页内容,点「商品详情」又显示另一套内容,但你注意到浏览器地址栏的 URL 在变

https://shop.com/          → 首页
https://shop.com/product/123 → 某个商品
https\n\n![Simple tech illustration expla](https://blog.xxyye.com/wp-content/uploads/2026/06/4dd5ed247e2bd04.png)\n\n![AI comic creation scene, creat](https://blog.xxyye.com/wp-content/uploads/2026/06/5adedc9dc33522b.png)\n\n://shop.com/cart       → 购物车

这背后就是「路由」在起作用。路由 = 根据不同 URL,显示不同页面/内容的规则。

上一章我们用「可复用 Modal 组件」解决了 UI 复用问题。这一章我们要解决一个新问题:当用户访问不同 URL 时,你的程序怎么知道该展示什么?

学完这章,你将能写出这样的程序:

# 用户访问 / 时,显示首页
# 用户访问 /hello 时,显示问候页面
# 用户访问 /user/小明 时,显示「你好,小明」

一个程序,多个页面,再也不用写一堆独立的 HTML 文件了。


🧱 基础 25 分钟:路由核心概念

什么是路由?—— 生活中的「分诊台」

想象你去医院挂号:

  • 护士问:「你挂什么科?」
  • 你说:「骨科」
  • 护士把你分到骨科诊室

路由就是这个分诊台:根据「地址」(URL),把你「分诊」到对应的处理函数。

为什么用路由?—— 不用路由会怎样?

假设不用路由,你要做 3 个页面:

# ❌ 不用路由:每个功能单独写一个文件
# index.html, about.html, contact.html...
# 维护痛苦、代码重复、无法传参

用路由之后:

# ✅ 用路由:一个程序搞定所有页面
# URL 就是入口,路由规则决定输出什么

第一个路由程序(Flask 版)

先安装 Flask:

pip install flask

然后写代码:

# app.py
from flask import Flask

app = Flask(__name__)

@app.route('/')  # 装饰器:告诉 Flask,「/」这个地址归我管
def home():
return '这是首页'

@app.route('/about')
def about():
return '这是关于页面'

if __name__ == '__main__':
app.run(debug=True)

运行:

python app.py

打开浏览器访问 http://127.0.0.1:5000/,看到「这是首页」

访问 http://127.0.0.1:5000/about,看到「这是关于页面」

就这么简单! @app.route('/xxx') 就是路由规则,def xxx() 就是处理函数。

动态路由:URL 里带参数

这是路由最强大的地方——URL 本身就是数据

比如访问 /user/小明,程序知道「小明」是用户名:

@app.route('/user/<username>')  # <username> 是变量
def user_profile(username):      # 处理函数接收这个变量
return f'这是用户:{username}的主页'

@app.route('/product/<int:product_id>')  # int: 表示只接受整数
def product_detail(product_id):
return f'商品ID:{product_id}'

类比<username> 就像信封上的收件人地址,Flask 自动帮你「拆信」取出名字。

# 访问 http://127.0.0.1:5000/user/小明
# 输出:这是用户:小明的主页

# 访问 http://127.0.0.1:5000/product/100
# 输出:商品ID:100

HTTP 方法:GET 和 POST

网页有不同的「操作类型」:

  • GET:获取数据(打开页面、搜索)
  • POST:提交数据(登录、注册、留言)
from flask import request

@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
    return '处理登录数据'
else:
    return '显示登录表单'

URL 反向生成:不用硬编码链接

写链接最怕「哪一天 URL 变了,全局替换」。

Flask 提供「反向生成 URL」:

from flask import url_for

@app.route('/home')
def home():
# 生成 /home 这个 URL
home_url = url_for('home')
return f'首页链接:{home_url}'
# 如果你需要跳转到 user_profile 页面
@app.route('/')
def index():
user_url = url_for('user_profile', username='小明')
return f'<a href="{user_url}">去小明的页面</a>'

好处:URL 变了不用改代码,Python 自动更新。


🔥 实战 35 分钟:3 个递进小项目

项目 1(5 分钟):个人作品集页面

跟着抄就能跑,一个多页面网站:

from flask import Flask

app = Flask(__name__)

@app.route('/')
def home():
return '''<html>
<body>
<h1>欢迎来到我的网站</h1>
<nav>
    <a href="/about">关于我</a> |
    <a href="/project/1">项目1</a> |
    <a href="/project/2">项目2</a>
</nav>
</body>
</html>'''

@app.route('/about')
def about():
return '''<html>
<body>
<h1>关于我</h1>
<p>我是小明,热爱编程</p>
<a href="/">返回首页</a>
</body>
</html>'''

@app.route('/project/<int:project_id>')
def project(project_id):
projects = {
    1: '待办清单 App',
    2: '天气查询工具',
    3: '个人博客系统'
}
name = projects.get(project_id, '未知项目')
return f'<h1>项目 {project_id}:{name}</h1><a href="/">返回首页</a>'

if __name__ == '__main__':
app.run(debug=True)

预期输出:访问 / 显示首页,点击链接能跳转到各子页面

一句话解释:用 @app.route() 定义 URL 规则,用 <int:id> 接收 URL 参数


项目 2(15 分钟):带数据的博客系统

从字典(模拟数据库)读取文章列表:

from flask import Flask

app = Flask(__name__)

# 模拟数据库
articles = {
1: {'title': 'Python 入门', 'content': '这是一篇关于 Python 基础的文章...'},
2: {'title': 'Flask 框架', 'content': 'Flask 是轻量级 Web 框架...'},
3: {'title': '数据库基础', 'content': '关系型数据库是...'}
}

@app.route('/')
def index():
html = '<h1>我的博客</h1><ul>'
for aid, article in articles.items():
    html += f'<li><a href="/article/{aid}">{article["title"]}</a></li>'
html += '</ul>'
return html

@app.route('/article/<int:article_id>')
def show_article(article_id):
article = articles.get(article_id)
if not article:
    return '<h1>文章不存在</h1><a href="/">返回首页</a>'
return f'''
<h1>{article["title"]}</h1>
<p>{article["content"]}</p>
<hr>
<a href="/">返回首页</a>
'''

if __name__ == '__main__':
app.run(debug=True)

预期输出:首页显示 3 篇文章标题,点击标题进入详情页

一句话解释:路由参数 article_id 就像「书页号」,帮你从字典里找到对应文章


项目 3(15 分钟):待办事项清单 API

结合路由 + 数据处理,写一个 RESTful API:

from flask import Flask, request, jsonify

app = Flask(__name__)

# 模拟数据库
todos = [
{'id': 1, 'title': '买菜', 'done': False},
{'id': 2, 'title': '做饭', 'done': True}
]
next_id = 3

@app.route('/api/todos', methods=['GET'])
def get_todos():
"""获取所有待办"""
return jsonify(todos)

@app.route('/api/todos', methods=['POST'])
def create_todo():
"""创建新待办"""
global next_id
data = request.json
todo = {'id': next_id, 'title': data['title'], 'done': False}
todos.append(todo)
next_id += 1
return jsonify(todo), 201

@app.route('/api/todos/<int:todo_id>', methods=['PUT'])
def update_todo(todo_id):
"""更新待办状态"""
for todo in todos:
    if todo['id'] == todo_id:
        todo['done'] = not todo['done']
        return jsonify(todo)
return jsonify({'error': 'Not found'}), 404

@app.route('/api/todos/<int:todo_id>', methods=['DELETE'])
def delete_todo(todo_id):
"""删除待办"""
global todos
todos = [t for t in todos if t['id'] != todo_id]
return jsonify({'message': 'deleted'})

if __name__ == '__main__':
app.run(debug=True)

测试方法(用 curl 或 Postman):

# 获取所有
curl http://127.0.0.1:5000/api/todos

# 创建新待办
curl -X POST http://127.0.0.1:5000/api/todos \
 -H "Content-Type: application/json" \
 -d '{"title":"洗碗"}'

# 切换完成状态
curl -X PUT http://127.0.0.1:5000/api/todos/1

# 删除
curl -X DELETE http://127.0.0.1:5000/api/todos/1

预期输出:完整的 CRUD 操作,返回 JSON 格式数据

一句话解释:RESTful API 就是「用 HTTP 方法操作资源」,URL 是资源,方法是动作


💪 进阶 20 分钟:常见坑 + 调试技巧

坑 1:路由顺序很重要!

# ❌ 错误:精确路由写在动态路由后面,永远匹配不到
@app.route('/user/<username>')
def user(username):
return f'用户:{username}'

@app.route('/user/admin')  # 这个永远不会执行!
def admin():
return '管理员页面'

# ✅ 正确:精确匹配放前面,动态路由放后面
@app.route('/user/admin')
def admin():
return '管理员页面'

@app.route('/user/<username>')
def user(username):
return f'用户:{username}'

坑 2:动态路由参数类型要匹配

# ❌ 错误:product_id 定义为 int,但传了字符串
@app.route('/product/<int:product_id>')
def product(product_id):
print(type(product_id))  # 还是 str!

# ✅ 正确:明确类型转换
@app.route('/product/<int:product_id>')
def product(product_id):
product_id = int(product_id)  # 显式转
return f'商品ID:{product_id}'

坑 3:methods 漏写导致 405 错误

# ❌ 错误:只定义了 GET,但前端发 POST
@app.route('/submit', methods=['GET'])  # 漏了 POST
def submit():
return '...'

# ✅ 正确:明确列出所有支持的 HTTP 方法
@app.route('/submit', methods=['GET', 'POST'])
def submit():
if request.method == 'POST':
    # 处理提交
return '表单页面'

坑 4:url_for 参数必须完整

# ❌ 错误:user_profile 需要 username 参数,但没传
@app.route('/test')
def test():
url = url_for('user_profile')  # 报错!

# ✅ 正确:动态路由的参数必须传入
@app.route('/test')
def test():
url = url_for('user_profile', username='小明')
return f'<a href="{url}">去小明的页面</a>'

坑 5:debug 模式在生产环境别开!

# ❌ 生产环境错误示例
app.run(debug=True)  # 暴露代码、容易被攻击

# ✅ 生产环境
app.run(debug=False, host='0.0.0.0', port=80)

调试技巧:用日志看请求详情

import logging

logging.basicConfig(level=logging.INFO)

@app.before_request
def log_request():
logging.info(f'请求方法: {request.method}, 路径: {request.path}')

✏️ 练习题 + 作业题

练习题(10 分钟)

练习 1(2 分钟):换个 URL

# 把项目 1 的 /about 改成 /me
# 预期输出:访问 /me 时显示「关于我」页面
  • 提示:改两处——装饰器参数和对应的 def 函数名

练习 2(2 分钟):加个条件判断

# 在项目 1 的 project 路由里,如果 project_id 是 3
# 返回「项目 3 是我最后一个项目!」
  • 提示:用 if project_id == 3 做判断

练习 3(3 分钟):换个数据源

# 用以下字典替换 articles,重新运行博客系统
books = {
1: {'title': '《红楼梦》', 'author': '曹雪芹'},
2: {'title': '《西游记》', 'author': '吴承恩'}
}
  • 提示:把 article 改成 book,把 content 改成 author

练习 4(3 分钟):串起两个项目

# 在项目 2 博客系统里,加一个 /api/count 接口
# 返回文章总数
  • 提示:参考项目 3 的 API 格式,用 len(articles) 获取数量

作业题(30 分钟-2 小时)

作业:做一个「个人名片管理器」

  • 需求:用 Flask 实现一个名片管理小工具
  • 功能点
    1. GET / - 显示所有名片列表
    2. GET /card/<int:card_id> - 查看单张名片详情
    3. POST /card - 新增名片(传入姓名、电话)
    4. DELETE /card/<int:card_id> - 删除名片
  • 加分项
    1. 用 url_for 生成链接,不用硬编码
    2. 名片数据持久化到文件(重启不丢失)
  • 验收标准:4 个接口都能正常调用并返回正确数据
  • 提交方式:评论区贴代码或 GitHub 链接

📚 总结 + 资源

本文学到的 3 个核心点
1. 路由 = URL 匹配规则@app.route('/path') 定义入口
2. 动态路由 = URL 传参<type:name> 从 URL 提取数据
3. RESTful = 资源 + HTTP 方法:GET 查、POST 增、PUT 改、DELETE 删

延伸学习资源
- Flask 官方文档 - 最权威的参考资料
- Django 路由系统 - 更复杂的路由玩法
- 《Flask Web 开发实战》- 深入浅出的 Flask 书籍

互动钩子

你在做哪个项目时遇到过「路由 404」的坑?或者你有更好的调试技巧?评论区聊聊,老粉优先回复!


下章预告

学会了路由,你已经能根据不同 URL 显示不同内容了。但如果有多个页面需要共享同一份数据(比如用户登录状态),怎么办?下一章我们要解决这个「数据传递」的大问题……

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。