> ## Documentation Index
> Fetch the complete documentation index at: https://docs.arupa.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# HTTP

> 在插件中处理动态 HTTP 请求。

HTTP 允许插件处理动态 HTTP 请求。当响应取决于请求数据、插件状态或应用程序逻辑时，请使用它。
内核匹配传入的请求，检查访问权限，将请求转换为插件协议，并将插件响应发送回客户端。
当内核可以直接提供文件时，请使用 [静态传输](./transport-static)。

## 声明 HTTP 路由

在插件注册期间声明每个 HTTP 路由。路由包含：

| 属性        | 含义                         |
| --------- | -------------------------- |
| `method`  | 要接受的 HTTP 方法。留空则接受模式的任何方法。 |
| `pattern` | 选择路由的 URL 路径。              |
| `access`  | 路由的可选访问策略。                 |

具体的声明语法取决于所使用的语言和生成的 SDK。以下与语言无关的格式显示了路由包含的信息：

```text theme={null}
method: POST
pattern: /my-plugin/items
access: <可选策略>
```

路由模式必须以 `/` 开头。查询字符串不属于模式的一部分。

例如，对 `/my-plugin/items?limit=10` 的请求匹配模式 `/my-plugin/items`；插件会收到 `limit=10` 作为请求数据。

## 路径匹配

HTTP 路由使用内核共享的路径模式语言。有关完整的模式和匹配规则，
请参阅 [内核路由匹配](../kernel/route)。

对于 HTTP 传输，以下情况很重要：

* 不以 `/` 结尾的模式匹配一个确切的路径。
* 以 `/` 结尾的模式匹配该路径及其子树。

例如：

```text theme={null}
/my-plugin/items → 仅 /my-plugin/items
/my-plugin/items/ → /my-plugin/items/ 及其子路径,例如 /my-plugin/items/42
```

根模式 `/` 仅匹配 HTTP 路由的 `/`。不支持通配符形式 `/*`。子树请使用尾随的 `/`。

当多个模式匹配同一路径时，匹配时间最长的模式优先。

内核会先选择路径，然后再选择方法。如果所选模式没有对应请求方法的路由，
客户端将收到 `405 Method Not Allowed` 错误。

精确匹配的方法路由优先于具有相同模式的任意方法路由。方法名称不区分大小写。

## 请求数据

发送到插件的请求是 Protobuf `HTTPRequest` 消息。请参阅[Protobuf](./proto) 文档以了解共享契约。
其字段如下：

| 字段              | Protobuf 类型           | 定义                         |
| --------------- | --------------------- | -------------------------- |
| `route_pattern` | `string`              | 已注册的与请求匹配的模式。              |
| `method`        | `string`              | HTTP 方法，例如 `GET` 或 `POST`。 |
| `path`          | `string`              | URL 路径，不包含查询字符串。           |
| `query`         | `string`              | 原始查询字符串，不包含前导的 `?`。        |
| `headers`       | `map<string, string>` | 以字符串键值对形式表示的请求头。           |
| `body`          | `bytes`               | 完整的请求体。                    |
| `remote_addr`   | `string`              | HTTP 服务器报告的远程地址。           |
| `user`          | `User`                | 已验证的用户（如有）。                |

`User` 消息包含一个 `username` 字符串和一个 `groups` 字符串列表。
对于未经身份验证的请求，`user` 不存在。

内核会在将请求体发送到插件之前对其进行缓冲。请求体大小限制为 8 MiB。超过此限制的请求会在插件处理程序运行之前被拒绝。

该协议将一个请求和一个响应表示为消息。它不提供流式请求或响应体，因此对于无法容纳在限制范围内的有效负载，请使用不同的设计。

## 返回响应

返回由 [Protobuf](./proto) 协议定义的 Protobuf `HTTPResponse` 消息。

其字段如下：

| 字段        | Protobuf 类型           | 定义               |
| --------- | --------------------- | ---------------- |
| `status`  | `int32`               | HTTP 状态码。        |
| `headers` | `map<string, string>` | 响应头以字符串键值对的形式表示。 |
| `body`    | `bytes`               | 响应体字节数。          |

如果省略状态或状态值为零，内核将使用 `200 OK`。
当客户端需要知道如何解析响应体时，请设置`Content-Type` 标头。

内核会将响应头和响应体复制到 HTTP 响应中。
如果插件处理程序在返回响应之前失败，内核将向客户端返回 `502 Bad Gateway` 响应。
在插件内部处理预期的应用程序错误，并返回相应的状态和响应体。

## 访问控制

内核在将请求转发到插件之前会评估访问权限。
请求必须同时满足为插件配置的插件级策略和路由上声明的策略。
如果任一策略拒绝请求，则处理程序不会运行。

空的路由策略不会覆盖插件级限制。
使用插件级策略来制定适用于所有资源的规则，
使用路由策略来制定更具体的规则。有关策略模型，请参阅[访问控制](../kernel/config-access)。

## 路由冲突

HTTP 路由与其他插件共享应用程序的 URL 空间，包括路由和静态挂载。
两个不同的插件不能声明相同的路径和方法。两个插件在处理不同方法时可以使用相同的路径，
前提是两个路由都不能接受所有方法。
一个接受所有方法的路由会与同一路径下所有特定于方法的路由冲突。
当两个插件声明相同的路径模式时，路由也会与另一个插件拥有的静态挂载冲突。

请将路由模式放在一个清晰的插件命名空间内，以避免冲突。

内核在连接注册期间返回的资源时会检查这些冲突。

冲突的路由不会被连接，但插件进程或WASM 实例仍然会启动。
该插件会被标记为“降级”，其他不冲突的资源仍然可用。
解决冲突并重新启动插件以注册缺失的路由。
这与加载包失败、启动后端失败或插件注册失败不同。
这些失败会阻止插件启动，并使其处于“失败”状态。

## HTTP 处理程序检查清单

加载插件前，请确认：

* 每个路由模式都以 `/` 开头；
* 子树使用尾随的 `/`，切勿使用 `/*`；
* 查询参数从请求数据中读取，而不是包含在路由模式中；
* 路由访问策略与处理程序保护的数据相匹配；
* 请求体大小不超过 8 MiB；以及
* 响应设置了适合客户端的状态、内容类型和响应体。

HTTP 是动态行为的理想选择。对于不需要处理程序的打包文件，
请使用[静态传输](./transport-static)。
