feat(plugin): error-page: support 403 and Nginx variables in body
- Dominant language
- Lua
- Stars
- 17.1k
- Forks
- 2.9k
- Avg merge
- 3d 16h
- Merged PRs (30d)
- 63
Description
### Description
### Description
The `error-page` plugin currently has two limitations that make custom error pages less useful in production:
**1. Limited status code coverage.** Only 404/500/502/503 are supported. APISIX-generated 403 responses are common — auth plugin rejections (key-auth, jwt-auth, etc.), ACL blocks, or custom serverless logic — but they cannot be replaced with a custom page.
**2. Static body only.** The configured `body` is returned as a static string. Operators typically want to embed request-scoped information into error pages — most importantly the **request ID**, so that end users can report it and administrators can correlate the error page with access/error logs.
### Proposal
**Part 1 — Support 403:**
- Add `error_403` to `metadata_schema` (same structure as existing entries)
- Lower the status threshold in `get_metadata` from `status < 404` to `status < 400`; interception still requires an explicitly configured `error_` key, so behavior for unconfigured codes is unchanged
**Part 2 — Nginx variables in body:**
- Resolve variables via `core.utils.resolve_var` (the same mechanism used by `response-rewrite` headers) before sending the response
- Resolution happens in `header_filter` so `Content-Length` is computed from the **final rendered body** (avoids truncation/connection stalls)
- Supports `$var`, `${var}`, the `??` default-value operator, and `\$` escaping
- Fail-open: on resolution failure, fall back to the original body and log a warning
- Zero overhead for existing configurations (bodies without `$` short-circuit before regex processing)
Example:
```json
{
"enable": true,
"error_403": {
"body": "
403 Forbidden
Request ID: $apisix_request_id
","content_type": "text/html"
}
}
```
Both parts are backward compatible and independent of each other, but they combine naturally — e.g. a custom 403 page showing `$apisix_request_id` for troubleshooting auth rejections.
Contributor guide
Research direction
Start with the error-page plugin's metadata_schema, get_metadata, and header_filter paths, then inspect core.utils.resolve_var usage in response-rewrite headers. Add 403 configuration support and render variables in the body before Content-Length is computed, preserving fail-open behavior and escaping/default syntax. Done means configured 403 pages and variable bodies work without changing unconfigured statuses or static-body behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- lua, nginx
- Domain
- api, backend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100