# 返回错误的方式

URL: https://caijiao.org/pingora/how_to_return_errors
Source: docs/pingora/how_to_return_errors.md
Description: 学习在 Pingora 中如何返回错误，包括自定义错误响应、状态码设置以及在不同阶段处理异常。

在 Pingora 中处理请求时，可能会遇到各种错误情况。  
合理返回错误可以保证客户端得到明确的响应，同时方便日志记录和监控。

## 错误类型

Pingora 使用 `Result<Response, Error>` 类型返回处理结果：

```rust
use pingora::prelude::*;

fn handle_request(req: &Request, _ctx: &mut Context) -> Result<Response, Error> {
    if req.path() == "/forbidden" {
        // 返回自定义错误
        return Err(Error::new("禁止访问", 403));
    }

    Ok(Response::new().with_body("请求成功"))
}
````

* `Ok(Response)`：正常响应
* `Err(Error)`：返回错误信息

## 设置 HTTP 状态码

在返回错误时，可以指定 HTTP 状态码：

```rust
let resp = Response::new()
    .with_status(500)
    .with_body("内部服务器错误");
return Err(Error::from(resp));
```

常用状态码：

| 状态码 | 含义      |
| --- | ------- |
| 400 | 请求格式错误  |
| 401 | 未认证     |
| 403 | 禁止访问    |
| 404 | 资源未找到   |
| 500 | 服务器内部错误 |
| 502 | 上游服务器错误 |
| 503 | 服务不可用   |

## 阶段内错误处理

在不同阶段返回错误的方式类似：

```rust
fn pre_filter(req: &Request, ctx: &mut Context) -> Result<(), Error> {
    if !req.headers().contains_key("X-Auth-Token") {
        return Err(Error::new("缺少身份验证令牌", 401));
    }
    Ok(())
}
```

* **Pre-filter**：请求前置阶段，可直接阻止请求
* **Response-filter**：响应阶段，可修改错误信息或日志记录

## 错误日志记录

返回错误时建议同时记录日志：

```rust
error!("请求 {} 返回错误: {:?}", req.path(), err);
```

结合配置的 `logging` 系统，可在日志文件或 systemd journal 中查看。

## 自定义错误响应示例

```rust
fn handle_error(err: Error, _ctx: &mut Context) -> Response {
    Response::new()
        .with_status(err.status_code())
        .with_body(format!("错误信息: {}", err.message()))
}
```

---

通过上述方式，你可以在 Pingora 中灵活处理请求错误，返回合适的 HTTP 状态码，并记录详细日志，确保服务稳定可靠。
