2024-09-17 01:00:39 +08:00

157 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SplitHTTPH2、QUIC H3
<Badge text="v1.8.16+" type="warning"/>
使用HTTP分块传输编码流式响应处理下载使用多个HTTP POST请求进行上传。
可以通过不支持WebSocket的CDN上但仍有一些要求
- CDN必须支持HTTP分块传输且支持流式响应而不会缓冲核心将会发送各种信息以告知CDN但是需要CDN遵守。如果中间盒不支持流式响应而导致连接被挂起则该传输很可能无法工作。
目的与V2fly Meek相同由于使用了流式响应处理下载下行速率更为优秀上行也经过优化但仍非常有限也因此对 HTTP 中间盒要求更高(见上)。
`SplitHTTP` 也接受 `X-Forwarded-For` header。
## SplitHttpObject
The `SplitHttpObject` 对应传输配置的 `splithttpSettings` 项。
```json
{
"path": "/",
"host": "xray.com",
"headers": {
"key": "value"
},
"scMaxEachPostBytes": 1000000,
"scMaxConcurrentPosts": 100,
"scMinPostsIntervalMs": 30,
"noSSEHeader": false,
"xPaddingBytes": "100-1000",
"xmux": {
"maxConnections": 0,
"maxConcurrency": 0,
"cMaxReuseTimes": 0,
"cMaxLifetimeMs": 0
}
}
```
> `path`: string
SplitHTTP 所使用的 HTTP 协议路径,默认值为 `"/"`
> `host`: string
SplitHTTP 的HTTP请求中所发送的host默认值为空。若服务端值为空时不验证客户端发送来的host值。
当在服务端指定该值,或在 ```headers``` 中指定host将会校验与客户端请求host是否一致。
客户端选择发送的host优先级 ```host``` > ```headers``` > ```address```
> `headers`: map \{string: string\}
仅客户端,自定义 HTTP 头,一个键值对,每个键表示一个 HTTP 头的名称,对应的值是字符串。
> `scMaxEachPostBytes`: int/string
上传分块的最大大小,单位为字节,默认值为 1000000, 即 1MB.
客户端设置的大小必须低于该值,否则当发送的 POST 请求大于服务端设置的值时,请求会被拒绝。
这个值应该小于CDN或其他HTTP反向代理所允许的最大请求体否则将抛出 HTTP 413 错误。
也可以是字符串 "500000-1000000" 的形式,核心每次会在范围内随机选择一个值,以减少指纹。
> `scMaxConcurrentPosts`: int/string
单个连接上传post的最大并发数默认为100.
上传并发同时也受(也主要受) `scMinPostsIntervalMs` 控制,故该值仅做保险。
客户端实际发起的数量必须低于服务端。(实际情况下由于上述很难达到上限,所以事实上客户端设置的值可以超过服务端,但不建议这么做)
也可以是字符串 "50-100" 的形式,核心每次会在范围内随机选择一个值,以减少指纹。
> `scMinPostsIntervalMs`: int/string
仅客户端发起POST上传请求的最小间隔。默认值为 30.
也可以是字符串 "10-50" 的形式,核心每次会在范围内随机选择一个值,以减少指纹。
> `noSSEHeader`: bool
仅服务端,不发送 `Content-Type: text/event-stream` 响应头,默认 `false` (即会发送)
> `xPaddingBytes` int/string
设置请求出站和响应入站的填充大小用于减少请求指纹。单位byte, 默认为 `"100-1000"` 每次会在该范围中随机选择一个数字。 也可以是单个数字 `"200"`/`200`
设置为 `-1` 将完全禁用填充
> `xmux`
允许用户对 SplitHTTP 在 h2 与 h3 中的多路复用行为进行控制,如不在次设置,默认行为为将所有请求复用至一条 h2/QUIC 连接。
与 mux.cool 不同,该复用工作于更低的等级,效率可能更好,如果有复用需求建议在此设置,不要启用 mux.cool.
术语解释:流会复用物理连接,像这样 连接1(流1,流2,流3) 连接2(流4,流5,流6) .. 以此类推 在其他地方你可能看到 连接-子连接 这样的描述,都是一样的东西。
* `maxConnections`: 默认值为 0(即无限) 要打开的最大连接数,连接达到此值时核心会积极打开连接,对每一条流都新建一个连接,直到达到该值。然后核心会开始复用已经建立的连接。 与 `maxConcurrency` 冲突。
* `maxConcurrency`: 默认值为 0(即无限) 每个连接中复用的流的最大数量,连接中流的数量达到该值后核心会新建更多连接以容纳更多的流,类似于 mux.cool 的 concurrency.
* `cMaxReuseTimes`: 默认值为 0(即无限) 一个连接最多被复用几次,当达到该值后核心不会向该连接再分配流,其将在内部最后一条流关闭后断开。
* `cMaxLifetimeMs`: 默认值为 0(即无限) 一个连接最多可以存活多久,当连接打开的时间超过该值后核心不会向该连接再分配流,其将在内部最后一条流关闭后断开。
## HTTP 版本
### 客户端行为
默认情况下,客户端将会默认在未启用 TLS 时使用 http/1.1, 启用 TLS 时,使用 h2.
当启用 TLS 时,允许在 TLS 设置的 alpn 数组内设置 http/1.1 h2 h3 来指定具体的http版本(仅当该数组只有一个元素时生效,若填入多个元素则返回默认行为)
### 服务端行为
默认情况下,服务端将会默认监听 TCP, 此时可以处理 http/1.1 和 h2 流量。
当启用 TLS 时,允许在 TLS 设置的 alpn 数组内设置 h3, 此时服务端将改为监听 UDP 端口, 处理 h3 流量。
### 小提示
由于该协议为标准的 HTTP 请求,所以对于 HTTP 版本的转换并不敏感,各种中间盒都可能转换 HTTP 版本。
列如:你希望使用 h3 连接 Cloudflare, 但是Cloudflare 不会使用 h3 回源, 而是使用 http/1.1 或 h2 回源,此时客户端 alpn 应为 h3, 而服务端就不应为 h3, 因为发往服务端的请求不是 h3.
## Browser Dialer
如果使用HTTPS该传输还支持 [Browser Dialer](../features/browser_dialer.md)
## 协议细节
讨论详见 [#3412](https://github.com/XTLS/Xray-core/pull/3412) 和 [#3462](https://github.com/XTLS/Xray-core/pull/3462) 以下是简述和简要兼容实现要求
1. 使用 `GET /<UUID>` 开始下载。服务器立即回复 `200 OK` 和 `Transfer Encoding:chunked` , 并立即发送一个两字节的有效负载以强制HTTP中间盒刷新标头。
现阶段服务器会发送以下标头
* `X-Accel-Buffering: no` 禁用缓冲
* `Content-Type: text/event-stream` 在部分中间盒中禁用缓冲,可以使用 `"noSSEHeader"` 选项关闭
* `Transfer-Encoding: chunked` 分块传输,仅在 HTTP/1.1 中使用
* `Cache-Control: no-store` to disable any potential response caching. 禁用CDN的缓存
2. 使用 `POST /<UUID>/<seq>` 开始发送上行数据. `seq` 作用类似于 TCP 序列号从0开始数据包可以被同时发送服务端必须按序列号将数据重组。序列号不应重置。
客户端可以以任意决定打开上行与下行请求的顺序任何一种都可以启动会话但是必须要在30秒内打开 `GET` 连接,否则会话将被终止。
3. `GET` 请求将一直保持在打开状态直到连接被终止服务端和客户端都可以关闭连接。具体行为取决于HTTP版本。
建议:
* 不要期望CDN会正确传输所有标头这个协议的目的是为了穿透不支持WS的CDN而这些CDN的行为通常不怎么友好。
* 应当假设所有HTTP连接都不支持流式请求所以上行连接发送的的每个包的大小应该基于延迟、吞吐量以及中间盒本身的限制考虑(类似TCP的MTU与纳格算法)。