一、URL的概念介绍
我们访问网站的某个页面,通常都是通过URL的方式来进行的,URL的全称为Uniform Resource Locator,中文名称是统一资源定位系统,是因特网的万维网服务程序上用于指定信息位置的表示方法。因此在介绍Flask Web应用程序中的URL路由前,我们先简单了解一下URL的相关知识。
URL按顺序主要由以下几个部分组成:
- 协议:告诉浏览器如何处理将要打开的文件。最常用的协议是超文本传输协议(Hypertext Transfer Protocol,缩写HTTP),这个协议可以用来访问网站。目前多数网站已经采用了更安全的超文本传输安全协议协议(Hypertext Transfer Protocol Secure,缩写HTTPS),相当于HTTP+SSL/TLS协议。其他常见的协议有FTP(文件传输协议)、SFTP(安全文件传输协议)、file(文件系统协议)等。
- 服务器地址:以最常见的HTTP协议为例,其完整形式的服务器地址规范如下:用户名:密码@服务器名称(域名或IP地址):端口号。其中”用户名:密码@“部分仅当服务器使用HTTP BASIC认证时才需要提供,目前新版本的浏览器(如基于Chromium的浏览器)已经不再允许在不安全的HTTP URL中直接传递认证参数了。如果使用的是HTTP协议,Web服务器的端口是80则端口号可以省略;同样的,如果使用的是HTTPS协议,Web服务器的端口是443则端口号也可以省略。
- 文件的路径和文件本身的名称:这里所说的路径和名称其实是URL路径,是开发者在编写Web应用程序和接口时通过URL路由的方式自定义的,和真实的文件在服务器硬盘上存档的路径和名称完全无关。这种方式的优点之一是可以通过在URL后附加不同的查询参数,通过固定的路径和名称就能够获取到后端动态生成的结果,便于前端调用接口,在接口开发中非常有用。
例如我的这个后端开发日志中有一篇文章是”Flask编程入门(三)第一个Flask代码“,其URL为https://www.brj.fan/34.html,其中https是协议名称;www.brj.fan是服务器地址;因为访问我的网站并不需要身份认证,因此省略了认证参数;由于使用的是HTTPS协议且我的Web服务器的端口是443,因此端口号部分省略;34.html是我这篇文章的路径和名称。
二、Flask中的URL路由
Flask中的URL路由实际上是通过Python的装饰器(函数)机制来实现的,初始化的APP对象中有一个route函数用于实现从URL到Python处理函数的映射,在Flask框架中这个函数也被称为”视图函数“(View Functions)。Flask允许开发者自定义路由,当某个用户访问特定URL时会调用指定的视图函数进行处理。
一个完整的Flask URL路由的定义方式如下:
from flask import Flask
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
@app.route('/index', methods=['POST'])
@app.route('/index.html', methods=['GET', 'POST'])
def index():
return 'Welcome to the Index Page!'
@app.route('/about', methods=['GET', 'POST'])
def about():
return 'This is the first About Page.'
@app.route('/about/', methods=['GET', 'POST'])
def about2():
return 'This is the second About Page.'
可以通过@app.route('URL路径')来定义一条URL路由,同一个视图函数可以对应于多条URL路由。此外,定义URL路由时可以指定允许使用的HTTP请求方法(GET、POST、PUT、DELETE、PATCH、HEAD、CONNECT、OPTIONS 和 TRACE),同一个视图函数对应的不同URL路由也可以分别指定允许使用的HTTP请求方法。另外,Flask Web应用程序中默认情况下OPTIONS方法一直是被允许的。


上面的代码中/index这条路由中,定义了只允许使用POST这一种请求方法,而我们在浏览器中直接访问这条URL使用的是GET方法,因此会产生HTTP 405状态码,即Method Not Allowed,请求方法不允许。


在上面的代码中我们定义了index.html这条URL路由,看起来很像是服务器上真实地存在着一个index.html的网页文件,但是由视图函数可以知道,我们只是在视图函数中返回了一段文本作为响应,项目文件中只有以下的文件,并不存在index.html这个文件。

因此可以说明,URL路径和真实的文件在服务器硬盘上存档的路径和名称完全无关。
此外,URL路径的某位是否有正斜杠”/“对于URL路由也是有影响的,例如上面的代码中有/about和/about/两条URL路由,分别对应于两个不同的视图函数,在浏览器中分别访问,结果如下:


可以看到,有斜杠和没有斜杠所对应的URL路径,所能够访问的页面是不一样的。如果只定义了”/about“这一条URL路由,那么访问”/about/“的URL路径则会产生HTTP状态码404,因为无法找到对应的路径或文件。这一点在编写URL路由的时候需要特别注意。
三、动态URL路由和对应的视图函数
很多情况下,URL路径中会包含一些变量,例如ID/用户名/日期等等,这时候就需要用到Flask框架中的动态URL路由的功能,URL路由中变量名需要用一对尖括号“<>”包括起来。
一个动态URL路由及其对应的视图函数如下所示:
@app.route('/print/<code>', methods=['GET', 'POST'])
def about2(code):
return code
访问http://127.0.0.1:5000/print/e3as1w2920,结果如下:

为了避免在视图函数中处理变量时遇到数据类型的问题,可以在URL路由和视图函数中增加变量类型提示符,Flask框架中定义了以下几种变量类型提示符:
变量类型提示符 | 变量类型说明 |
string | 默认值,字符串类型,不能包含斜杠”/“ |
int | 无符号整型,只接受正整数 |
float | 无符号浮点型,只接受正浮点数 |
path | 字符串类型,可以包含斜杠”/“,用于动态指定路径 |
uuid | UUID对象类型 |
因为string类型是默认值,上面的代码已经展示了,接下来介绍剩下的几种类型:
(1)int类型
@app.route('/print/<int:num>', methods=['GET', 'POST'])
def print_int(num: int):
return "Num: %d" % num
访问http://127.0.0.1:5000/print/223,结果如下:

注意:int类型只接受正整数参数,如果是负整数则会被视为默认值的字符串类型,匹配到上面字符串的URL路由中。例如访问http://127.0.0.1:5000/print/-223,结果如下:

(2)float类型
@app.route('/print/<float:fnum>', methods=['GET', 'POST'])
def print_float(fnum: float):
return "FNum: %f" % fnum
访问http://127.0.0.1:5000/print/223.19,结果如下:

注意:float类型只接受正浮点数参数,如果是负浮点数则会被视为默认值的字符串类型,匹配到上面字符串的URL路由中。例如访问http://127.0.0.1:5000/print/-223,结果如下:

(3)path类型
@app.route('/print/<path:pth>', methods=['GET', 'POST'])
def print_path(pth: str):
return "My Path: %s" % pth
访问http://127.0.0.1:5000/print/test/12/3.2,结果如下:

(4)uuid类型
@app.route('/print/<uuid:uid>', methods=['GET', 'POST'])
def print_uuid(uid: uuid.UUID):
return f"UUID: {uid}"
访问http://127.0.0.1:5000/print/38D886FD-12AE-EB03-6447-340BAB263B1E,结果如下:
