具有可百分比编码固定部分(空格、非 ASCII)的动态路由无法访问,url_for() URL 返回 404
作者: Yanhaoxi创建于 2026年8月16日更新于 2026年8月17日
标签bug
描述错误
动态路径(和静态/前缀资源),其固定路径段包含需要百分位编码的字符——一个空间,非ASCII,或一些保留字符——是无法到达的:对它们的每一个请求返回404,由"url for()"生成的URL也不能返回.
固定部分在注册时为%- 编码( requote path' ), 编码表用于**** 资源索引密钥和匹配模式。 但UrlDispatcher.resolve'通过走出已编码的`request.rel.url.path safe' 来选择候选人。 因此编码的索引密钥从未被探测过,因此资源也从未成为候选.
示例 : app.router.add get ("/hello world/{name}"), 处理器, name="greet" “编译为正文 : /hello% 20world/{name} 和索引键 /hello% 20world' 。 要求“/hello%20world/john”解码为“/helloworld/john”,而后行探测器“/helloworld/john”,“/helloworld”,“/'——永远不“/hello%20world”——所以是404s。 这同样适用于Static Refour'前缀(app.router.add static ("/static文件/",".)'在/static%20files/.'上无法达到')。
在aiohttp 3.14.3和主人身上验证。
相关编码(aiohttp 3.14.3),`aiohttp/web urldispatcher.py':
DynamicResources. init编码了固定部件,并使用了编码格式,用于标出材料和图案文字:part = requote path(part)'(:457)和pattern += re.escape(part)'(:459);`self. formatter = formatter'(:468)。- `DynamicResources.canonical'返回编码为物质的(:471-472)。
- QQGet resource index key” 的索引密钥取自编码的条形文字 (:1110-1119): 对于“/hello% 20world/{name} 密钥是 `/hello% 20world' 。
- " 解决 " 向后行走decod路径(`url part = request.rel url.path safe ' :1033;循环:1034-1043;没有候选人参加时404;1048)。
重写
导入 Ayncio
从 aiohttp 导入网页
async def 主 () - > 无:
app=网络. 应用程序( )
# 有可编码的固定段( 空间) 的动态路径
app.router.add get ("/hello world/{name}"), lambda r: web.Response (text=r.match info ["name"]), name="greet" (中文(简体) ).
# 有相同固定部分(控制:工程)的平坦路线
app.routter.add get ("/hello world/"),羊陀螺:web. 答复(文本=“平面”))
runder=web.AppRunner(应用程序)
正在等待 runder. setup( )
站点=web.TCPSite(运行者,"127.0.0.1","8080")
等待站点. start ()
aync def get(路径:str) - > 无:
导入 aiohttp
以 aiohttp. Client Session () 作为会话 :
async with session.get(f"http://127.0.0.1:8080{path}"作为resp:
打印(f"GET {path:24} - > {resp.status}}")
等待 get ("/ hello% 20world/") # plain 路由 - > 200
等待获取("/hello%20world/john") #动态路由 - > 404(预期200)
等待 get(str (app.router) ["greet"].url for(name="john"))# url for - > 404
等待跑者。 清除( )
ayncio.run(主要())输出 :
控制台 获取 . . . . . . .
内容来源: aio-libs/aiohttp