#基于官网所写
#现代 Web 应用使用有意义的 URL,方便用户记忆、提高访问率。
#基于上篇Flask所写,传统套娃中
#如果是萌新强烈建议从我的Flask简单入门开始看
一.动态门牌(URL可以带变量)
前面我们写的门牌 /、/about 都是固定不变的地址。
现在我们多加一块可变门牌 <name>:网址最后一截可以随便填内容,Flask 会抓到这个内容传给函数。
from flask import Flask from markupsafe import escape # 新增:拿来给文字上锁、转义 app = Flask(__name__) # 门牌1:网站大门首页 / @app.route('/') def home(): return '欢迎来到我的观影清单首页!' # 门牌2:关于页面 /about @app.route('/about') def about(): return '实时更新' # 门牌3:可变门牌(新知识点,动态URL) @app.route("/<name>") def hello(name): return f"Hello, {escape(name)}!"案例展示:
/<name> 里的 <name> 相当于一个收纳框。
访问 http://127.0.0.1:5000/喵喵
页面就输出:Hello, 喵喵!
⚠️ 为什么要用 escape ()?(HTML 转义)
如果有人在网址输入这种内容:
http://127.0.0.1:5000/<script>alert("bad")</script>
不加 escape():浏览器识别 <script>,直接运行这段 JS 代码,属于注入漏洞
加上 escape():<、> 这类符号被转义,页面只把它当成普通文字展示,不会执行代码
后面我们学模板的时候,Jinja 模板会自动帮我们转义;
像现在这样直接 return 文字,用户可控的数据,就要手动写 escape。
官网说明:
直接 return 文本的这种写法,Flask不会自动转义,用户可控的数据必须手动用 escape。
等到后面我们用 Jinja HTML 模板写页面,模板会自动帮我们转义,就不用每次手动写 escape 了。
官网很多示例为了简洁省略 escape,但正式写项目不能忽略安全问题!
(1.1)变量类型转换器
默认 <name> 只能接收字符串,不能接收斜杠 /。
Flask 支持给变量加类型限制,语法:<类型:变量名> | <string:name>
# 1.只接收正整数(文章id、用户id) @app.route('/post/<int:post_id>') def show_post(post_id): return f"文章编号:{post_id}" # 2.接收带斜杠的完整路径(文件路径) @app.route('/files/<path:subpath>') def show_path(subpath): return f"文件路径:{subpath}"内置转换器对照表:
1.string(默认):匹配除 / 以外所有文本
2.int:只匹配正整数
3.float:只匹配正小数
4.path:匹配包含 / 的完整路径
(1.2)多个URL绑定同一个函数
可以把多个路由规则绑定到同一个视图函数
# 访问 / 或者 /index 都会进入同一个函数 @app.route('/') @app.route('/index') def index(): return 'Index Page'进阶写法
from flask import Flask from markupsafe import escape # 新增:拿来给文字上锁、转义 app = Flask(__name__) @app.route("/hello") @app.route("/hello/<name>") def greet(name=None): if name is None: return "Hello World" return f"Hello, {escape(name)}!"如果报错404 not found 看下自己找的网址对不都下划线后面需要加hello,进阶版本需要添加/everyone(你自己也可以输入其他的不一定非要是everyone,最后返回会根据你输入的返回)
(1.3)路由斜杠小坑
1./about 和 /about/ 是两条完全不同的地址
2.访问 /about/ 会出现 404 找不到页面
3.想自动补全斜杠,可以在路由末尾加上 /:@app.route('/about/')
一.2 固定路由
@app.route('/') def index(): return 'Index Page' @app.route('/hello') def hello(): return 'Hello, World'这种就是地址写死的静态门牌,访问 /hello 才会触发这个函数。
二.HTML转义
HTML 转义(HTML escaping):把 HTML 里有特殊功能的符号,替换成普通文字代码,让浏览器只把内容当成纯文本展示,不会把它当成标签、JS 代码来执行,用来防止 XSS 脚本注入攻击。
1.原理
<、>、& 在 HTML 里是有特殊作用的:
< 代表标签开始(<script>)
> 代表标签结束
& 代表转义字符开头
浏览器看到这些符号,就会自动解析成网页代码。
转义就是把这些符号 “降级成普通文字”。
2.核心字符对应表(escape 做的就是这件事)
| 原字符 | 转义后代码 | 作用 |
|---|---|---|
< | < | 小于号,防止开启标签 |
> | > | 大于号,防止闭合标签 |
& | & | 防止被识别成转义开头 |
" | " | 双引号 |
' | ' | 单引号 |
3.对应 Flask 代码的例子
(1).未转义(危险)
用户输入:<script>alert("bad")</script>
浏览器识别为 JS 脚本,直接弹出弹窗,造成 XSS 攻击。
(2).经过 escape () 转义之后(安全)
字符串自动变成:
<script>alert("bad")</script>
浏览器只会把整段内容原样显示在页面上,不会执行任何代码。
4.HTML 转义部分补充安全知识点(完善 XSS 内容)
# 危险写法!不要自己拼html标签 return f"<h1>{user_input}</h1>" # 必须加上escape return f"<h1>{escape(user_input)}</h1>"5.模板里的安全红线
1.Jinja 模板默认自动转义;
2.不要随便使用 |safe 过滤器,一旦开启,用户输入就不再转义,直接产生 XSS 漏洞;
3.只有自己编写的可信 HTML 内容,才允许标记为 safe。
#一句话安全铁律
只要内容来自用户输入(URL、表单、网址参数),一律要做 HTML 转义;只有自己写死的固定文字才不需要转义。
补充知识点
1.直接用 return 返回字符串:必须手动调用 escape() 做 HTML 转义;
2.使用 Jinja2 HTML 模板:模板会自动完成 HTML 转义,不需要手动写 escape;
3.官网示例经常省略 escape 简化代码,但是正式项目绝对不能省略。
小总结:
1.动态路由:<变量名> 抓取 URL 内容,传给函数参数,变量名必须和函数形参完全一致;
2.变量转换器:<int:id>、<path:subpath> 限制参数类型,严格匹配 URL;
3.多路由绑定:多个 @app.route 装饰器可以共用同一个函数;
4.HTML 转义:escape() 把 < > & 转为字符实体,阻止 XSS 脚本注入;
5.安全原则:原生 return 字符串必须手动 escape;Jinja 模板自动转义,禁止随意关闭自动转义