apache / apache/apisix

feat(plugin): error-page: support 403 and Nginx variables in body

Open
#13,742 0 comments 0 reactions 0 assignees View on GitHub
enhancement
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.