文档Python API 和错误
异常和错误
一个请求可能会在四个地方失败,并且 Nexy 对每个地方的响应都不同。此页面是索引:找到您看到的状态,然后是生成它的行,然后是决定正文的文件。
简短版本
| 发生了什么 | 状态 | 浏览器看到 | API客户端看到 |
|---|---|---|---|
| 没有路由与 URL 匹配 | 404 |
notfound.nexy,否则为内置页面 |
{"detail": "Not Found"} |
| 路径段不适合其注释 | 404 |
同一页 | {"detail": "Not Found"} |
| 查询、标头、cookie 或正文字段丢失或无效 | 422 |
FastAPI 的 JSON 正文 | FastAPI 的 JSON 正文 |
notFound() |
404 |
页面 | {"detail": ...} |
unauthorized() |
401 |
内置页面 | {"detail": ...} |
forbidden() |
403 |
内置页面 | {"detail": ...} |
raise HTTPException(409, ...) |
409 |
内置页面 | {"detail": ...} |
| 没有捕获任何异常 | 500 |
errors.nexy,否则为内置页面 |
{"detail", "reference"} |
redirect(url) |
307 |
目的地,无页面 | 目的地,没有尸体 |
permanentRedirect(url) |
308 |
目的地,无页面 | 目的地 |
API 客户端是一个请求,其 Accept 标头要求 JSON,而不是页面:
curl -H "Accept: application/json" http://localhost:3000/api/items/500# {"detail":"Out of range"}
失败从何而来
Browser ──► Middleware ──► Router ──► Page or handler
│ │ │
│ │ ├─ return ───────────► 200
│ │ ├─ HTTPException ────► its status
│ │ └─ other exception ───► 500
│ └─ no match ────────────────────────► 404
└─ raises ──────────────────────────────────────► 500| 舞台 | 什么会失败 | 答案 |
|---|---|---|
| 中间件 | 您的 middleware.py、CORS、会话 |
异常的状态,否则 500 |
| 路由器 | URL 不匹配任何文件 | 404 |
| 验证 | 路径段无法转换 | 404 |
| 验证 | 查询、标头、cookie 或正文字段 | 422 |
| 页面、处理程序、操作、防护 | HTTPException |
它的状态 |
| 页面、处理程序、操作、防护 | 还有什么 | 500 |
从任何地方离开
redirect、permanentRedirect、notFound、forbidden 和 unauthorized 引发 HTTP 异常,因此相同的调用在 .nexy 页面、API 处理程序、模块化控制器、防护、dependencies.py 和操作中工作。
from nexy import notFound, redirect from src.posts import find async def GET(slug: str): post = find(slug) if post is None: notFound("No such post") if post.moved_to: redirect(post.moved_to) return postfrom nexy import notFound, redirectfrom nexy.decorators import Controller from src.posts import find @Controller("/posts/{slug}")class PostsBySlugController: async def get(self, slug: str): post = find(slug) if post is None: notFound("No such post") if post.moved_to: redirect(post.moved_to) return post在根模块的 controllers 中列出控制器。
| 致电 | 回答 | 当 |
|---|---|---|
notFound(detail=None) |
404 |
该资源不存在 |
unauthorized(detail=None, scheme=None) |
401 |
访客必须先登录 |
forbidden(detail=None) |
403 |
访客是已知的,但可能看不到此内容 |
redirect(url, status=307) |
307 |
将它们发送到其他地方,保留方法 |
redirect(url, status=303) |
303 |
表单之后:下一个请求是 GET |
permanentRedirect(url) |
308 |
搜索引擎应该记住的移动页面 |
根据您信任的价值观打造目的地。 redirect(request.query_params["next"]) 将访问者发送到链接所在的任何地方;这是一个开放的重定向。包含换行符的目的地将被拒绝。
验证:422 或 404
处理程序参数由 FastAPI 根据其注释进行验证。
from nexy.http import Header async def GET(q: str, limit: int = 10, x_token: str = Header(...)): return {"q": q, "limit": limit}from nexy.decorators import Controllerfrom nexy.http import Header @Controller("/api/search")class SearchApiController: async def get(self, q: str, limit: int = 10, x_token: str = Header(...)): return {"q": q, "limit": limit}在根模块的 controllers 中列出控制器。
| 问题 | 状态 | 为什么 |
|---|---|---|
| 查询、标头、cookie 或正文字段缺失或无效 | 422 |
请求到达处理程序,数据错误 |
无效路径段(id: int 的 /api/users/abc) |
404 |
该文件夹没有非号码的路由,因此该 URL 不存在 |
422 主体是 FastAPI 的标准形状,因此客户端和生成的 SDK 可以继续工作:
{"detail": [{"loc": ["query", "q"], "msg": "Field required", "type": "missing"}]}
对于表单或操作,客户端会收到带有 status 和 detail 的 ActionError; a 422 还为每个字段填充一条消息 error.fields。请参阅操作。
自定义错误页面
<h1>Page not found</h1><p>The link may be old. <a href="/">Start from the home page</a>.</p><h1>Something went wrong</h1><p>Try again in a moment.</p>| 文件 | 状态 | 适用范围 |
|---|---|---|
src/routes/notfound.nexy |
404 |
项目的每条路线 |
src/routes/errors.nexy |
500 |
项目的每条路线 |
src/routes/forbidden.nexy |
403 |
项目的每条路线 |
src/routes/unauthorized.nexy |
401 |
项目的每条路线 |
src/routes/blog/notfound.nexy |
404 |
/blog 及以下 |
src/routes/blog/errors.nexy |
500 |
/blog 及以下 |
src/routes/loading.nexy |
- | 保留,还没有运行时效果 |
路由中某处的一个文件会安装其状态的答案:根目录中的副本会回答整个项目,文件夹中的副本会回答该文件夹,而与 URL 匹配的最深文件将获胜。每个副本外部的 URL 以及根本没有文件的状态,获取内置样式的页面。请参阅每个文件夹的错误页。
模块化路由器的文件中没有错误页面:404、500、403 或 401 获取内置样式页面。每个文件夹的错误页面是基于文件的路由器的约定。
未处理的异常
一个例外是,没有捕获任何内容都会被记录一次,并包含其引用、它来自哪里以及它周围的代码。状态是 500,身体取决于环境。
nexy dev |
nexy build 然后 nexy start |
|
|---|---|---|
| 浏览器 | 错误、代码行和回溯 | errors.nexy,否则内置页面,带有参考 |
| API客户端 | {"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}
参考号是八个字符,每次失败都是新的。访问者可以引用它,您可以通过在日志中搜索它来找到回溯。异常和代码都不会到达生产中的访问者。
动作和形式
操作是具有生成路径的 POST 端点。它的失败遵循相同的规则:
| 情况 | 状态 | 客户 |
|---|---|---|
| 字段缺失或无效 | 422 |
ActionError 与 fields |
HTTPException(403) 在行动中提出 |
403 |
ActionError 与 status 和 detail |
| 未处理的异常 | 500 |
ActionError;参考位于服务器日志中 |
Origin 标头是另一个站点 |
403 |
在操作运行之前被拒绝 |
没有 JavaScript 的表单发布到操作路径;成功则返回 303 页面,失败则显示错误页面。请参阅操作。
当页面回答错误时的清单
- 查看状态,而不是页面。自定义
notfound.nexy仍会回答404。 - 读取终端。 导入失败的页面未注册,因此当文件存在时其 URL 会回答
404。导入错误在日志中。 - 检查扩展名。 与
useCSR = True、.nexy页面属于服务器模式;错误模式的页面不是路由。 - 检查深度。
notfound.nexy或errors.nexy仅在根副本存在时才有效。 - 请求 JSON 和
Accept: application/json以查看 API 客户端收到的形状。 - 当您打开问题或搜索日志时,引用
500的参考文献。