PostgREST 错误处理完全指南:错误结构、HTTP 状态码映射与自定义错误 📅 发布时间:2026/9/11 10:19:30 👁 浏览次数: PostgREST 错误处理完全指南错误结构、HTTP 状态码映射与自定义错误【免费下载链接】postgrestREST API for any Postgres database项目地址: https://gitcode.com/GitHub_Trending/po/postgrestPostgREST 将 PostgreSQL 数据库直接转化为 RESTful API其错误处理机制也因此与 PostgreSQL 的报错体系深度绑定错误响应保留了 PostgreSQL 的MESSAGE、DETAIL、HINT、ERRCODE结构并叠加 HTTP 状态码供客户端消费。本文基于 docs/references/errors.rst 与仓库源码Error.hs、Error/Types.hs、ErrorSpec.hs完整讲解 PostgreSQL 错误如何被转发、错误码如何映射为 HTTP 状态、PostgREST 自身PGRST错误码分组以及如何通过RAISE语句自定义状态码与响应头。读完本文你将能在实际 API 开发中准确诊断错误响应、并让数据库函数返回完全定制化的 HTTP 错误。统一的错误响应结构PostgREST 的错误消息遵循 PostgreSQL 的错误结构响应体为 JSON包含以下四个字段字段来源说明messagePostgreSQLMESSAGE人类可读的错误主信息detailsPostgreSQLDETAIL补充细节可能为nullhintPostgreSQLHINT修复建议可能为nullcodePostgreSQLERRCODE五字符错误码如23502PostgREST 会在该结构之上附加一个 HTTP 状态码。无论是来自 PostgreSQL 的错误、PostgREST 自身的错误还是自定义错误这一 JSON 骨架始终不变区别仅在code字段的值。从源码看这一结构由ErrorBody与ErrorHeaders两个 typeclass 统一抽象见 Error.hserrorResponseFor负责把任意错误对象序列化为 HTTP 响应设置Content-Type: application/json、Content-Length、Proxy-Status以及错误自身的头并将code/message/details/hint编码为 JSONError.hs。所有内部错误类型ApiRequestError、SchemaCacheError、JwtError、PgError都实现了这两个 class因此对外呈现完全一致的错误格式。PostgreSQL 错误的转发与 HTTP 状态码映射错误转发示例PostgREST 会原样转发来自 PostgreSQL 的错误。例如向/projects表插入违反非空约束的数据POST /projects HTTP/1.1返回HTTP/1.1 400 Bad Request Content-Type: application/json; charsetutf-8{ code: 23502, details: Failing row contains (null, foo, null)., hint: null, message: null value in column \id\ of relation \projects\ violates not-null constraint }这里的code即 PostgreSQL 官方错误码表errcodes-appendix中的23502not_null_violation。PostgreSQL 错误码 → HTTP 状态码映射表PostgREST 将 PostgreSQL 错误码翻译为 HTTP 状态码规则如下PostgreSQL 错误码HTTP 状态码错误描述08*503pg connection err09*500triggered action exception0L*403invalid grantor0P*403invalid role specification23503409foreign key violation23505409uniqueness violation25006405read only sql transaction25*500invalid transaction state28*403invalid auth specification2D*500invalid transaction termination38*500external routine exception39*500external routine invocation3B*500savepoint exception40*500transaction rollback53400500config limit exceeded53*503insufficient resources54*500too complex55*500obj not in prerequisite state57*500operator intervention58*500system errorF0*500config file errorHV*500foreign data wrapper errorP0001400default code for raiseP0*500PL/pgSQL errorXX*500internal error42883404undefined function42P01404undefined table42P17500infinite recursion42501已认证 403否则 401insufficient privilegesother400—映射的源码实现这张表并非文档虚构而是由 Error.hs 中mapSQLtoHTTP函数逐条实现。此外源码还包含几个映射表未列出的细化分支属于值得注意的实现细节21000cardinality_violation通常返回 500但当错误消息以requires a WHERE clause结尾时pg-safeupdate 插件场景被视为客户端错误返回 400。22023invalid_parameter_value当消息以role开头、以does not exist结尾时说明 JWT 中的角色不存在返回 401其余情况返回 400。42883undefined function若消息以function xmlagg(开头则返回 406否则返回 404。57P01admin shutdown返回 503。PTxyz自定义状态码分支见下文自定义错误一节。PGRST完全自定义响应分支。mapSQLtoHTTP的第二个参数authed是否已认证只影响42501的判定已认证返回 403未认证返回 401。测试用例should return 500 for cardinality_violation与should return 500 for statement too complexErrorSpec.hs分别验证了21000与54001映射为 500。PostgREST 自身错误PGRST 前缀PostgREST 自身的错误保持相同的 JSON 结构但code字段带有PGRST前缀以此与 PostgreSQL 错误区分。例如请求一个在 schema cache 中不存在的函数POST /rpc/nonexistent_function HTTP/1.1返回HTTP/1.1 404 Not Found Content-Type: application/json; charsetutf-8{ hint: ..., details: null, code: PGRST202, message: Could not find the api.nonexistent_function() function in the schema cache }错误码的命名规则PostgREST 错误码形如PGRSTgxxPGRST前缀用于与 PostgreSQL 错误区分g错误分组xx组内错误标识符。源码中通过注释明确规定了分组约定Error.hsPGRST0xx连接错误、PGRST1xxAPI 请求错误、PGRST2xxSchemaCache 错误、PGRST3xxJWT 认证错误、PGRSTXxx内部 Hasql 错误新分组追加在所有分组末尾且所有码保留PGRST前缀以方便 grep 搜索。对应的数据类型定义在 Error/Types.hs 中按组注释分区。Group 0 —— 连接PGRST0xx与数据库连接相关CodeHTTP 状态码描述PGRST000503因db-uri配置错误或 PostgreSQL 服务未运行无法连接数据库PGRST001503因内部错误无法连接数据库PGRST002503构建 Schema Cache 时无法连接数据库PostgreSQL 服务未运行PGRST003504等待连接池分配连接超时参见 db-pool-acquisition-timeout 配置源码层面PGRST000对应SQL.ConnectionUsageErrorPGRST001对应SQL.ClientErrorPGRST003对应SQL.AcquisitionTimeoutUsageErrorPGRST002是NoSchemaCacheErrorError.hs 与 Error.hs。其中db-pool-acquisition-timeout的默认值为 10 秒用于控制请求等待连接池释放槽位的最大时长。Group 1 —— API 请求PGRST1xx与 HTTP 请求元素相关CodeHTTP 状态码描述PGRST100400查询字符串参数解析错误参见过滤条件、操作符与排序PGRST101405函数RPC只允许GET和POST动词其他动词会触发此错误PGRST102400请求体无效如空请求体或畸形 JSONPGRST103416分页Range范围无效PGRST105405无效的 PUTUPSERT 请求PGRST106406切换 schema 时指定的 schema 不在 db-schemas 配置变量中PGRST107406请求中的Accept媒体类型无效PGRST108400过滤条件应用到了未在select查询参数中指定的嵌入资源参见嵌入过滤PGRST111500设置了无效的response.headers参见 guc_resp_hdrsPGRST112500状态码必须是正整数参见 guc_resp_statusPGRST114400使用 PUT 进行 UPSERT 时同时使用了分页PGRST115400使用 PUT 进行 UPSERT 时查询字符串中的主键与请求体不一致PGRST116406请求单数响应singular response时返回了多于 1 个或 0 个结果参见单数/复数PGRST117405请求使用的 HTTP 动词不受支持PGRST118400无法使用关联表排序因为两者之间不存在多对一或一对一关系PGRST120400嵌入资源只能使用is.null或not.is.null操作符进行过滤PGRST121500PostgREST 无法解析 RAISEPGRST错误中的 JSON 对象参见RAISE 响应头PGRST122400Prefer: handlingstrict下出现无效偏好Prefer 头参见 prefer_handlingPGRST123400聚合函数被禁用参见 db-aggregates-enabledPGRST124400max-affected偏好被违反参见 prefer_max_affectedPGRST125404请求 URL 中指定了无效路径PGRST126404OpenAPI 配置被禁用但仍访问了 API 根路径参见 openapi-modePGRST127400details字段中指定的功能未实现PGRST128400调用 RPC 时max-affected偏好被违反参见 prefer_max_affected该组在源码中的映射一目了然Error.hs 中code、message、details、hint的实例定义与文档表格一一对应。例如PGRST108NotEmbedded在未指定别名时 hint 为Verify that resource is included in the select query parameter.指定别名时则提示改为使用别名。Group 2 —— Schema CachePGRST2xx与 schema cache 相关。大多数情况下这类错误可通过重新加载 schema cache 解决CodeHTTP 状态码描述PGRST200400外键关系过期导致否则可能是嵌入资源或关系本身在数据库中不存在PGRST201300请求了有歧义的嵌入参见复杂关系PGRST202404函数签名过期导致否则函数可能不存在于数据库PGRST203300请求了同名参数但类型不同的重载函数或用POST调用带未命名JSON/JSONB参数的重载函数。解决方法是重命名函数或为参数添加/修改名称PGRST204400columns查询参数中指定的列不存在PGRST205404URI 中指定的表不存在这类错误的一个亮点是模糊匹配提示fuzzy hint当表或函数未找到时PostgREST 会基于相似度给出 Perhaps you meant ... 建议。实现位于noRelBetweenHint、noRpcHint、tableNotFoundHint等函数Error.hs表名与函数名的模糊搜索要求相似度 ≥ 0.75而函数参数的模糊搜索使用更低阈值0.33。ErrorSpec.hs 用三个用例验证了这一阈值行为/projectx≥75% 相似给出 hint、/projxxxx75% 相似hint 为null。Group 3 —— JWTPGRST3xx与 JWT 认证过程相关。完整的认证实现示例可参考教程 tut1更多细节见认证文档CodeHTTP 状态码描述PGRST300500配置中缺少 JWT secretPGRST301401提供的 JWT 无法解码或无效PGRST302401未配置 db-anon-role 导致匿名角色被禁用时未携带 Bearer 认证发起请求PGRST303401JWT claims 校验或解析失败该组的消息文本非常具体例如PGRST301的细分原因包括Empty JWT is sent in Authorization header、Expected 3 parts in JWT; got n、Wrong or unsupported encoding algorithm、JWT cryptographic operation failed等PGRST303则覆盖JWT expired、JWT not yet valid、JWT issued at future、JWT not in audience以及exp/nbf/iat/aud声明类型错误等Error.hs。另外401 类 JWT 错误会附带WWW-Authenticate: Bearer响应头其中PGRST301/PGRST303使用errorinvalid_token形式的详细描述Error.hs。ErrorSpec.hs 覆盖了错误密钥、不存在角色等场景。Group X —— 内部错误PGRSTXxx内部错误。如果遇到这类错误很可能是 PostgREST 的 bug应提交 issue 以便修复CodeHTTP 状态码描述PGRSTX00500与数据库连接库Hasql相关的内部错误自定义错误用 RAISE 掌控响应你可以通过在函数中使用 PostgreSQL 的RAISE语句来自定义错误。基础 RAISE默认返回 400自定义状态码可以通过在函数中抛出 SQL 异常实现。例如一个总是返回错误的函数CREATE OR REPLACE FUNCTION just_fail() RETURNS void LANGUAGE plpgsql AS $$ BEGIN RAISE EXCEPTION I refuse! USING DETAIL Pretty simple, HINT There is nothing you can do.; END $$;调用该函数返回 HTTP 400响应体为{ message:I refuse!, details:Pretty simple, hint:There is nothing you can do., code:P0001 }这是因为普通RAISE EXCEPTION的错误码是P0001而P0001在映射表中对应 HTTP 400。利用既有映射RAISE 特定异常另一种定制状态码的方式是利用 PostgREST 的错误码到状态码映射例如RAISE insufficient_privilege会按映射返回 401 或 403取决于是否已认证。PTxyz任意三位数状态码若需要更精细的控制可以抛出PTxyz类型的异常其中xyz为任意三位数字状态码。例如要返回 HTTP 402RAISE sqlstate PT402 using message Payment Required, detail Quota exceeded, hint Upgrade your plan;返回HTTP/1.1 402 Payment Required Content-Type: application/json; charsetutf-8{ message: Payment Required, details: Quota exceeded, hint: Upgrade your plan, code: PT402 }源码中P:T:n分支会读取PT后的数字并构造对应 HTTP 状态Error.hs。注意若PT后不是数字如PT40A则回退为 500——RpcSpec.hs 的用例defaults to status 500 if RAISE code is PT not followed by a number验证了这一点。仓库测试夹具中也定义了等价函数schema.sql。PGRST SQLSTATE完全控制状态码与响应头若需要对状态码和响应头进行完全控制可以抛出PGRSTSQLSTATE 错误。做法是在 PostgreSQL 错误的message字段中以 JSON 对象形式放入code、message、detail、hint其中details和hint可选再在错误detail字段中以 JSON 对象形式放入status和headers。例如RAISE sqlstate PGRST USING message {code:123,message:Payment Required,details:Quota exceeded,hint:Upgrade your plan}, detail {status:402,headers:{X-Powered-By:Nerd Rage}};返回HTTP/1.1 402 Payment Required Content-Type: application/json; charsetutf-8 X-Powered-By: Nerd Rage{ message: Payment Required, details: Quota exceeded, hint: Upgrade your plan, code: 123 }对于非标准 HTTP 状态码可额外添加status_text字段描述该状态码。例如状态码 419 的 detail 字段可以写成detail {status:419,status_text:Page Expired,headers:{X-Powered-By:Nerd Rage}};仓库测试夹具 schema.sql 中定义了此类函数使用自定义状态 332、状态文本My Custom Status以及自定义头X-HeaderRpcSpec.hs 的多个用例验证了从PGRSTRAISE 中提取消息、详情、标准/自定义状态文本以及解析失败时的行为。解析失败与 PGRST121如果 PostgREST 无法解析message与detail中的 JSON 对象将抛出PGRST121错误HTTP 500。其details会区分三种情况Invalid JSON value for MESSAGE: ...、Invalid JSON value for DETAIL: ...、DETAIL is missing in the RAISE statementhint 则提示MESSAGE必须包含必填键code、message与可选键details、hintDETAIL必须包含必填键status、headers与可选键status_textError.hs。底层解析逻辑parseRaisePGRST使用 Aeson 将字节串解码为PgRaiseErrMessage与PgRaiseErrDetailsError.hs。Proxy-Status 响应头对于错误场景PostgREST 会返回标准的Proxy-Status响应头其中携带错误码。错误码来源可以是 PostgREST 错误、PostgreSQL 错误或自定义错误。这在执行HEAD请求时尤其有用——此时 HTTP 状态码本身描述性不足Proxy-Status能提供精确的错误码。例如对一个大表假设 3000 万行发起请求HEAD /table HTTP/1.1 Prefer: countexact返回HTTP/1.1 500 Internal Server Error Proxy-Status: PostgREST; error57014其中的 PostgreSQL 错误码57014query_canceled揭示了根因statement_timeout设置过短导致查询被取消。该头的格式由 Error.hs 的pSHeader生成即Proxy-Status: PostgREST; errorcodeErrorSpec.hs 分别验证了 API 请求错误PGRST125、SchemaCache 错误PGRST205、JWT 错误PGRST301、PT402自定义错误以及PGRST自定义错误场景下的Proxy-Status头。客户端错误详略度client-error-verbosityHTTP 客户端收到的错误详略度可通过 client-error-verbosity 配置控制支持三种设置方式配置文件、环境变量PGRST_CLIENT_ERROR_VERBOSITY或数据库内 GUCpgrst.client_error_verbosity该配置可热重载默认值为verbose。verbose默认返回code、message、details、hint四个字段。curl localhost:3000/itemsxx{ code: PGRST205, message: Could not find the table public.itemsxx in the schema cache, details: Perhaps you meant the table public.items, hint: null }minimal仅返回code和message。curl localhost:3000/itemsxx{ code: PGRST205, message: Could not find the table public.itemsxx in the schema cache }该设置只影响发送给客户端的错误信息不影响服务端日志。实现上errorPayload根据Verbosity枚举构造 JSONVerbose输出四字段Minimal只输出code与messageError.hs。ErrorSpec.hs 通过configClientErrorVerbosity Minimal验证了details与hint被隐藏的行为。实践建议快速定位问题优先看响应体中的code字段。PGRST前缀代表 PostgREST 自身逻辑问题查本文错误码表即可定位纯数字如23505、23503代表数据库约束问题57014等代表数据库运行期问题。利用 hint 字段PGRST205、PGRST202等 SchemaCache 错误的hint通常包含基于模糊匹配的修正建议如Perhaps you meant the table public.items可直接据此修正请求路径。HEAD 请求排查当状态码信息不足时读取响应的Proxy-Status头获取精确错误码。业务错误定制在数据库函数中用RAISE sqlstate PTxxx返回符合业务语义的三位数状态码需要附带自定义头时使用PGRSTSQLSTATE 的 JSON 消息格式但务必保证 JSON 合法否则会得到PGRST121。安全考量生产环境可考虑将client-error-verbosity设为minimal避免向客户端暴露过多内部细节。【免费下载链接】postgrestREST API for any Postgres database项目地址: https://gitcode.com/GitHub_Trending/po/postgrest创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考