LocalSend 协议 v2
本协议由 Jesse205 使用 Deepl 汉化自 github.com/localsend/p…。
我们的目标是制定一个不依赖任何外部服务器的简单 REST 协议。
由于计算机网络可能很复杂,我们不能假设每种方法都可用。 有些设备可能不支持组播,或者不允许运行 HTTP 服务器。
这就是为什么本协议试图“聪明”一点,使用多种方法来发现并向其他 LocalSend 成员发送文件。
该协议只需要一方设置 HTTP 服务器。
目录
暂不支持
1. 默认
LocalSend 不需要特定的端口或组播地址,而是提供默认配置。
如果端口/地址不可用,一切都可以在应用程序设置中进行配置。
默认组播组为 224.0.0.0/24,因为有些安卓设备拒绝接受任何其他组播组。
多播 (UDP)
- 端口: 53317
- 地址: 224.0.0.167
HTTP (TCP)
- 端口: 53317
2. 指纹
指纹用于避免自我发现和记忆设备。
当加密开启 (HTTPS) 时,指纹是证书的 SHA-256 哈希值。
关闭加密 (HTTP) 时,指纹是随机生成的字符串。
3. 发现
3.1 多播 UDP (默认)
广播:
程序启动时,将向组播组发送以下信息:
{
"alias": "Nice Orange",
"version": "2.0", // 协议版本 (major.minor)
"deviceModel": "Samsung", // nullable
"deviceType": "mobile", // mobile | desktop | web | headless | server, nullable
"fingerprint": "随机字符串",
"port": 53317,
"protocol": "https", // http | https
"download": true, // 下载 API (5.2 和 5.3) 是否激活 (可选,默认为 false)
"announce": true
}
响应:
其他 LocalSend 成员会注意到这条信息,并回复各自的信息。
首先,向原设备发送 HTTP/TCP 请求:
POST /api/localsend/v2/register
{
"alias": "Secret Banana",
"version": "2.0",
"deviceModel": "Windows",
"deviceType": "desktop",
"fingerprint": "随机字符串", // 在 HTTPS 模式下被忽略
"port": 53317,
"protocol": "https",
"download": true, // 下载 API (5.2 和 5.3) 是否激活 (可选,默认为 false)
}
作为后备措施,成员也可以使用 多播/UDP 信息进行响应。
{
"alias": "Secret Banana",
"version": "2.0",
"deviceModel": "Windows",
"deviceType": "desktop",
"fingerprint": "随机字符串",
"port": 53317,
"protocol": "https",
"download": true,
"announce": false,
}
fingerprint 仅用于避免自我发现。
只有当 announce 为 true 时,才会触发响应。
3.2 HTTP (传统模式)
当组播不成功时,应使用此方法。
通过向所有本地 IP 地址发送此请求来发现设备。
POST /api/localsend/v2/register
请求:
{
"alias": "Secret Banana",
"version": "2.0", // 协议版本 (major.minor)
"deviceModel": "Windows",
"deviceType": "desktop",
"fingerprint": "随机字符串", // 在 HTTPS 模式下被忽略
"port": 53317,
"protocol": "https", // http | https
"download": true, // 下载 API (5.2 和 5.3) 是否激活 (可选,默认为 false)
}
响应:
{
"alias": "Nice Orange",
"version": "2.0",
"deviceModel": "Samsung",
"deviceType": "mobile",
"fingerprint": "随机字符串", // 在 HTTPS 模式下被忽略
"download": true, // 下载 API (5.2 和 5.3) 是否激活 (可选,默认为 false)
}
4. 文件传输 (HTTP)
这是默认方法。
接收方设置 HTTP 服务器。
发送方 (即 HTTP 客户端) 向 HTTP 服务器发送文件。
4.1 准备 (仅元数据)
只向接收方发送元数据。
接收方将决定是否接受、部分接受或拒绝该请求。
POST /api/localsend/v2/prepare-upload
请求
{
"info": {
"alias": "Nice Orange",
"version": "2.0", // 协议版本 (major.minor)
"deviceModel": "Samsung", // 可为空
"deviceType": "mobile", // mobile | desktop | web | headless | server, 可为空
"fingerprint": "随机字符串", // 在 HTTPS 模式下被忽略
"port": 53317,
"protocol": "https", // http | https
"download": true, // 下载 API (5.2 和 5.3) 是否激活 (可选,默认为 false)
},
"files": {
"文件ID": {
"id": "文件ID",
"fileName": "我的图片.png",
"size": 324242, // bytes
"fileType": "image/jpeg",
"sha256": "*sha256哈希值*", // 可为空
"preview": "*预览数据*" // 可为空
},
"另一个文件ID": {
"id": "另一个文件ID",
"fileName": "另一个图片.jpg",
"size": 1234,
"fileType": "image/jpeg",
"sha256": "*sha256哈希值*",
"preview": "*预览数据*"
}
}
}
响应
{
"sessionId": "我的会话ID",
"files": {
"文件ID": "文件Token",
"另一个文件ID": "另一个文件Token"
}
}
错误
| HTTP 代码 | 信息 |
|---|---|
| 204 | 完成 (无需传输文件) |
| 400 | 无效请求体 |
| 403 | 拒绝 |
| 500 | 接收器未知错误 |
4.2 发送文件
文件传输。
使用来自 /prepare-upload 的 sessionId、fileId 及其特定于文件的 token。
此路由可并行调用。
POST /api/localsend/v2/upload?sessionId=我的会话ID&fileId=文件ID&token=文件Token
请求
二进制数据
响应
无响应体
错误
| HTTP 代码 | 信息 |
|---|---|
| 400 | 参数缺失 |
| 403 | 无效令牌或 IP 地址 |
| 409 | 被其他会话阻止 |
| 500 | 接收器未知错误 |
4.3 取消
当发送方要取消会话时,将调用此路由。
使用 /send-request 中的 sessionId 。
POST /api/localsend/v2/cancel?sessionId=我的会话ID
响应
无响应体
5. 反向文件传输 (HTTP)
这是一种替代方法,当接收方无法使用 LocalSend 时应使用这种方法。
发送方设置一个 HTTP 服务器,通过提供一个 URL 发送文件给其他成员。
然后,接收方使用给定的 URL 打开浏览器并下载文件。
值得注意的是,由于浏览器拒绝接受自签名证书,因此使用的是未加密的 HTTP 协议。
5.1 浏览器 URL
接收者可在浏览器中打开以下 URL 下载文件。
http://<发送者ip>:<发送者端口>
5.2 接收请求 (仅元数据)
向发送方发送获取文件元数据列表的请求。
下载程序可能会添加 ?sessionId=我的会话ID 。在这种情况下,如果是同一会话,则应接受请求。
如果用户刷新浏览器页面,就需要这样做。
POST /api/localsend/v2/prepare-download
请求:
无请求体
响应:
{
"info": {
"alias": "Nice Orange",
"version": "2.0",
"deviceModel": "Samsung", // 可为空
"deviceType": "mobile", // mobile | desktop | web | headless | server, 可为空
"fingerprint": "随机字符串", // 在 HTTPS 模式下被忽略
"download": true, // 下载 API (5.2 和 5.3) 是否激活 (可选,默认为 false)
},
"sessionId": "mySessionId",
"files": {
"文件ID": {
"id": "文件ID",
"fileName": "我的图片.png",
"size": 324242, // bytes
"fileType": "image/jpeg",
"sha256": "*sha256哈希值*", // 可为空
"preview": "*预览数据*" // 可为空
},
"另一个文件ID": {
"id": "另一个文件ID",
"fileName": "另一个图片.jpg",
"size": 1234,
"fileType": "image/jpeg",
"sha256": "*sha256哈希值*",
"preview": "*预览数据*"
}
}
}
5.3 接收文件
文件传输
使用 /receive-request 中的 sessionId 和 fileId 。
该路由可以并行调用。
GET /api/localsend/v2/download?sessionId=我的会话ID&fileId=文件ID
请求:
无请求体
响应:
二进制数据
6. 附加应用程序接口
6.1 信息
这是以前用于发现的旧路由。现在已被 /register 所取代,这是一种双向发现方式。
现在,这条路由只能用于调试目的。
GET /api/localsend/v2/info
响应:
{
"alias": "Nice Orange",
"version": "2.0",
"deviceModel": "Samsung", // 可为空
"deviceType": "mobile", // mobile | desktop | web | headless | server, 可为空
"fingerprint": "随机字符串",
"download": true, // 下载 API (5.2 和 5.3) 是否激活 (可选,默认为 false)
}
7. 枚举
在本项目中,枚举用于定义某些字段的可能值。
7.1 设备类型
设备类型仅用于显示图标等用户界面目的。
不同设备类型之间的协议没有区别。
| 值 | 描述 |
|---|---|
| mobile | 移动设备 (Android, iOS, FireOS) |
| desktop | 桌面 (Windows, macOS, Linux) |
| web | 网页浏览器 (Firefox, Chrome) |
| headless | 在终端运行的无图形用户界面程序 |
| server | 全天候运行的(自托管)云服务 |
实现处理未知值。官方实现会退回到 desktop。