文档处理程序和错误
错误页面
失败的请求仍应像站点的其余部分一样进行响应:对于访问者来说,是一个用您自己的话表示的页面,与 API 客户端的 JSON 失败相同。 Nexy 回答了这两个问题,并用一个文件替换每个答案。
此页面是地图:哪个文件回答哪个状态,以及如何制作您的第一个。文件夹的页面有它们自己的页面。
一次失败,两种答案
a request that fails
│
├── a browser (Accept: text/html) ──► an HTML page
└── an API client (Accept: application/json) ──► {"detail": "…"} with the same status
the HTML page
├── the deepest folder of the URL that holds a file ──► your file
└── no folder of the chain holds one ──► the built-in page您的第一页
创建 src/routes/notfound.nexy 并写入访问者应该阅读的内容:
metadata = {"title": "Page not found"}<h1>Page not found</h1><p>The page moved or never existed. <a href="/">Back home</a>.</p>保存并请求 URL,但没有任何服务:
curl -i -H "Accept: text/html" http://localhost:3000/nowhere# HTTP/1.1 404 Not Found
路由根目录下的文件回答了整个项目;文件夹中的副本仅响应该文件夹并保持其余部分不变。无需任何文件,Nexy 即可提供其内置样式页面。
哪个文件回答
| 文件 | 答案 |
|---|---|
notfound.nexy |
404 为其目录 |
errors.nexy |
500 为其目录 |
forbidden.nexy |
403 为其目录 |
unauthorized.nexy |
401 为其目录 |
loading.nexy |
保留;还没有运行时效果 |
| 情况 | 回答 |
|---|---|
| 没有路线匹配 | 404 |
| 动态段无法转换为其注释 | 404 |
| 页面或 API 处理程序中未处理的异常 | 500 |
raise HTTPException(status_code=403) |
您提出的状态,HTML 或 JSON 格式 |
notFound(),forbidden(),unauthorized() |
404、403、401,来自请求中的任何位置 |
redirect(),permanentRedirect() |
真正的重定向,没有错误页面 |
通过代码留下页面或答案
redirect、permanentRedirect、notFound、forbidden 和 unauthorized 引发 HTTP 异常,因此相同的调用在 .nexy 页面、API 处理程序、模块化控制器、防护和 dependencies.py 中工作。它们在客户端上具有相同的名称 (@nexy/client)。
from nexy import notFound, redirect from src.posts import find slug: prop[str]post = find(slug)if post is None: notFound()if post.moved_to: redirect(post.moved_to)<h1>{{ post.title }}</h1>| 致电 | 回答 |
|---|---|
redirect(url) |
307; redirect(url, status=303) 将表单后的 POST 转换为 GET |
permanentRedirect(url) |
308;浏览器和搜索引擎会记住它 |
notFound(detail=None) |
404:notfound 页面,或 API 客户端的 JSON |
forbidden(detail=None) |
403:访问者是已知的,但可能看不到此内容 |
unauthorized(detail=None, scheme=None) |
401; scheme="Bearer" 添加 WWW-Authenticate |
重定向响应带有 Location 标头,但没有页面,也返回到 API 客户端。根据您信任的价值观构建目的地:redirect(request.query_params["next"]) 将访问者发送到链接所说的任何地方。带有换行符的目的地将被拒绝。
警卫保护整个文件夹:
from nexy import unauthorizedfrom nexy.http import Request def require_login(request: Request) -> None: if not request.session.get("user"): unauthorized(scheme="Bearer") dependencies = [require_login]HTML 或 JSON
对于相同的异常,不同的提问者会给出不同的答案:
- 浏览器 (
Accept: text/html) 获取 HTML 页面。详细信息是 HTML 转义的,因此根据用户输入构建的消息无法注入标记。 - 请求 JSON 而不是页面 (
Accept: application/json) 的客户端会获得具有相同状态代码的{"detail": "..."}。
from nexy.http import HTTPException async def GET(id: int): if id > 100: raise HTTPException(status_code=403, detail="Out of range") return {"id": id}curl -H "Accept: application/json" http://localhost:3000/api/items/500# {"detail":"Out of range"}
未处理的异常
没有任何处理的异常会被记录一次,除了异常的来源和周围的代码,并根据模式进行回答。
nx dev |
nx start |
|
|---|---|---|
| 浏览器 | 包含错误的页面、引发错误的代码行以及完整的回溯 | 带有参考的内置 500 页面(或您的 errors.nexy) |
| JSON客户端 | {"detail", "reference", "error"} |
{"detail", "reference"} |
| 服务器日志 | 异常和代码行 | 异常和整个回溯,具有相同的引用 |
x ZeroDivisionError: division by zero GET /boom ref fe6a5217 at src/routes/boom.py:2 in GET 1 | def GET(): 2 | return {"a": 1 / 0}
参考号是八个字符,每次失败都是新的。访问者可以引用它,您可以通过在日志中搜索它来找到回溯。异常和代码都不会到达生产中的访问者。自定义 errors.nexy 仅替换页面;日志行保留。
验证错误
对于每个客户端,缺少标头、查询参数或正文字段都会使用 FastAPI 的 JSON 正文回答 422。请参阅验证和错误。
后续步骤
- 每个文件夹的错误页面:一个文件夹中您自己的 404、403 或 401
- 动态路线
- API 路由
- 测试