Python 现代开发学习笔记

(六)方法与路径共同决定路由

1. 先找路径,再确认可执行的动作

同样的 /api/books,GET 表示读取,POST 表示新增;不能只看到路径相同就调用同一段动作。

# 项目文件:web_project/src/webbook/routing.py
# 先比较路径再比较方法;路径存在但方法不匹配时返回405及Allow。
import re

from .http import Problem

ROUTES = [
    (r"/", {"GET": "home"}),
    (r"/login", {"GET": "login_page", "POST": "login"}),
    (r"/logout", {"POST": "logout"}),
    (r"/books", {"POST": "create_form"}),
    (r"/api/session", {"GET": "session_info"}),
    (r"/api/books", {"GET": "book_list", "POST": "create_json"}),
    (r"/api/books/(?P<book_id>[1-9][0-9]*)", {"GET": "book_detail"}),
    (r"/api/books/(?P<book_id>[1-9][0-9]*)/finish", {"POST": "finish"}),
    (r"/assets/(?P<name>app\.css|app\.js)", {"GET": "asset"}),
]


def route(method, path):
    for pattern, methods in ROUTES:
        match = re.fullmatch(pattern, path)
        if match:
            if method not in methods:
                raise Problem(
                    405,
                    "这个路径不接受该请求方法",
                    headers=[("Allow", ", ".join(methods))],
                )
            return methods[method], match.groupdict(), list(methods)
    raise Problem(404, "没有找到这个地址")

re.fullmatch 要求整个路径符合模式。(?P<book_id>...) 给捕获部分取名,match.groupdict 返回 {"book_id":"1"} 这样的参数字典;handler 是我们给分支取的名字,后面由应用组合对应动作。

模式中的 [1-9] 匹配一个非零数字,[0-9]* 接着匹配零个或多个数字;字符串前的 r 保留反斜杠本身,例如静态文件名中的 \. 表示字面上的句点。

路径存在但方法不支持时返回 405,并用 Allow 列出支持的方法;路径本身没有匹配时返回 404。静态资源也只接受表中列出的文件名,不把任意 URL 直接拼成可读取的本地路径。

同一路径先找到入口,再按GET或POST选择动作,不支持的方法进入405,未匹配路径进入404

笔记正文与全部题解 · Ctrl / ⌘ K