适合读者:想在 Rust 后端服务、内部 CLI、可信 Worker 中直接把大文件上传到阿里云 OSS,或从 OSS 断点下载文件的开发者。
1. 先说结论:直连模式只适合可信环境
rusty-cat 支持阿里云 OSS direct 模式,也就是运行 Rust 程序的进程直接持有阿里云 AccessKey,并在本地为 OSS 请求签名。
这个模式适合:
- 后端服务。
- 内部运维 CLI。
- 私有化部署 Worker。
- CI/CD 或数据处理任务。
不适合:
- 桌面客户端直接内置 AccessKey Secret。
- 移动 App 直接内置 AccessKey Secret。
- 浏览器或公开分发的软件。
原因很简单:**AccessKey Secret 是长期密钥,一旦放到用户机器里,就有被提取的风险。**如果是用户侧应用,建议看下一篇"阿里云 OSS 预签名上传下载",让后端签发短期 URL,客户端只拿临时授权。
本文不会出现任何真实 AccessKey、Secret、Bucket 或业务地址。示例全部使用环境变量和占位名称,复制运行前请替换为你自己的安全配置。
2. rusty-cat 在 OSS 直连模式里解决什么?
如果你自己手写 OSS 分片上传,需要处理:
- 创建 multipart upload。
- 按分片上传 part。
- 查询已上传 part 以支持恢复。
- 所有 part 成功后 complete multipart upload。
- 取消时清理 multipart session。
- 下载时对
HEAD和 RangeGET加 OSS 签名。 - 每个分片失败后的重试。
- 上传/下载进度回调。
- 多任务并发控制。
rusty-cat 把通用调度交给 MeowClient,把阿里云 OSS 签名和 multipart 细节封装到:
AliOssDirectUploadAliOssDirectDownload
你要做的是:准备配置、构造任务、注入 OSS 协议插件、提交任务。
3. 依赖与 feature
如果使用 GitHub 当前发布文档中的版本,可以这样写:
toml
[dependencies]
rusty-cat = { version = "0.2.2", features = ["aliyun-oss-direct"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
如果你的项目基于本地源码 0.1.1,核心 API 写法基本一致,但正式接入时仍建议以 crates.io 和 docs.rs 对应版本为准:
aliyun-oss-direct feature 会启用阿里云 OSS 直连签名相关能力。生产环境不要为了省事直接启用 all,只打开自己需要的 provider feature。
4. 需要哪些参数?
阿里云 OSS 直连上传和下载都需要这些值:
| 参数 | 示例 | 是否敏感 | 说明 |
|---|---|---|---|
bucket |
my-bucket |
否 | OSS Bucket 名称。 |
access_key_id |
从环境变量读取 | 是 | 阿里云 AccessKey ID。不要写死在代码里。 |
access_key_secret |
从环境变量读取 | 是 | 阿里云 AccessKey Secret。绝对不要提交到 Git。 |
region |
cn-beijing |
否 | Bucket 所在区域。 |
object_key |
uploads/demo.bin |
否 | OSS 对象路径。 |
object_url |
https://{bucket}.oss-{region}.aliyuncs.com/{object_key} |
通常否 | 目标对象 URL。不要在 URL 里拼接密钥。 |
推荐通过环境变量读取密钥:
bash
export ALIYUN_ACCESS_KEY_ID="REDACTED_ACCESS_KEY_ID"
export ALIYUN_ACCESS_KEY_SECRET="REDACTED_ACCESS_KEY_SECRET"
上面只是占位写法。文章、截图、日志和 Git 仓库里只应该出现变量名或 REDACTED,不应该出现真实值。
5. OSS 直连上传完整示例
下面示例展示如何上传本地 ./demo.bin 到 OSS。
rust
use std::sync::Arc;
use rusty_cat::aliyun_oss_direct::AliOssDirectUpload;
use rusty_cat::api::{MeowClient, MeowConfig, UploadPounceBuilder};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let bucket = "my-bucket";
let region = "cn-beijing";
let object_key = "uploads/demo.bin";
let access_key_id = std::env::var("ALIYUN_ACCESS_KEY_ID")?;
let access_key_secret = std::env::var("ALIYUN_ACCESS_KEY_SECRET")?;
let object_url = format!(
"https://{bucket}.oss-{region}.aliyuncs.com/{object_key}"
);
let config = MeowConfig::builder()
.max_upload_concurrency(1)
.build()?;
let client = MeowClient::new(config);
let upload_protocol = AliOssDirectUpload::new(
bucket,
access_key_id,
access_key_secret,
region,
);
let task = UploadPounceBuilder::new(
"demo.bin",
"./demo.bin",
1024 * 1024,
)
.with_url(object_url)
.with_breakpoint_upload(Arc::new(upload_protocol))
.with_max_chunk_retries(3)
.build()?;
let outcome = client
.enqueue_and_wait(task, |record| {
println!(
"OSS 上传进度:file={} progress={:.2}% status={:?}",
record.file_name(),
record.progress() * 100.0,
record.status(),
);
})
.await?;
println!("上传完成:task_id={} payload={:?}", outcome.task_id, outcome.payload);
client.close().await?;
Ok(())
}
运行前注意:
./demo.bin必须存在。my-bucket、cn-beijing、uploads/demo.bin要替换成你自己的 Bucket、Region 和对象路径。- 环境变量必须设置,不能把 AccessKey Secret 直接写到源码里。
- Bucket 权限要允许对应 AccessKey 执行 multipart upload、list parts、complete multipart upload 等操作。
6. 上传参数逐个解释
| 代码 | 说明 |
|---|---|
MeowConfig::builder().max_upload_concurrency(1) |
控制同时运行的上传任务组数量。初次接入建议从 1 开始,避免并发过高影响 OSS 或本地磁盘。 |
AliOssDirectUpload::new(bucket, access_key_id, access_key_secret, region) |
创建阿里云 OSS 直连上传协议对象。密钥只保存在内存中的协议对象里,SDK 不会替你写入数据库。 |
UploadPounceBuilder::new(file_name, file_path, chunk_size) |
创建上传任务。chunk_size 单位是字节,1024 * 1024 表示 1 MiB。 |
with_url(object_url) |
设置 OSS 对象最终 URL。直连协议会从 URL 中识别对象路径。 |
with_breakpoint_upload(Arc::new(upload_protocol)) |
把阿里云上传协议注入任务。需要 Arc,因为后台执行器可能跨 async task 使用协议对象。 |
with_max_chunk_retries(3) |
单个分片失败后最多额外重试 3 次。 |
enqueue_and_wait(...) |
提交任务并等待完成。CLI 或简单程序推荐先用它。 |
client.close().await |
显式关闭后台调度器,生产代码不要省略。 |
7. OSS 直连下载完整示例
下载时使用 AliOssDirectDownload。SDK 会执行 HEAD 获取大小,再用 Range GET 下载分片,provider 插件会为请求添加 OSS 签名。
rust
use std::sync::Arc;
use rusty_cat::aliyun_oss_direct::AliOssDirectDownload;
use rusty_cat::api::{DownloadPounceBuilder, MeowClient, MeowConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let bucket = "my-bucket";
let region = "cn-beijing";
let object_key = "uploads/demo.bin";
let access_key_id = std::env::var("ALIYUN_ACCESS_KEY_ID")?;
let access_key_secret = std::env::var("ALIYUN_ACCESS_KEY_SECRET")?;
let object_url = format!(
"https://{bucket}.oss-{region}.aliyuncs.com/{object_key}"
);
let client = MeowClient::new(MeowConfig::default());
let download_protocol = AliOssDirectDownload::new(
bucket,
access_key_id,
access_key_secret,
region,
);
let task = DownloadPounceBuilder::new(
"demo.bin",
"./downloads/demo.bin",
1024 * 1024,
object_url,
)
.with_breakpoint_download(Arc::new(download_protocol))
.with_max_chunk_retries(3)
.build();
let outcome = client
.enqueue_and_wait(task, |record| {
println!(
"OSS 下载进度:file={} progress={:.2}% status={:?}",
record.file_name(),
record.progress() * 100.0,
record.status(),
);
})
.await?;
println!("下载完成:task_id={}", outcome.task_id);
client.close().await?;
Ok(())
}
运行前注意:
./downloads目录要存在,或者由业务代码提前创建。- AccessKey 要有读取该对象的权限。
- 本地日志不要打印
access_key_secret。
8. 直连模式的安全清单
| 检查项 | 建议 |
|---|---|
| 密钥来源 | 使用环境变量、密钥管理服务或部署平台 Secret,不要写死在代码里。 |
| Git 提交 | 检查 .env、配置文件、测试脚本,避免把密钥提交到仓库。 |
| 日志 | 不打印 AccessKey Secret,不打印包含敏感签名信息的完整调试内容。 |
| 数据库 | 传输表里只存 credential_ref,不要存原始 Secret。 |
| 权限 | AccessKey 使用最小权限,只允许目标 Bucket 和必要操作。 |
| 客户端 | 公开客户端不要使用 direct 模式,改用预签名 URL。 |
| 轮换 | 定期轮换 AccessKey,并确保服务能平滑加载新密钥。 |
9. 如何和业务数据库配合?
rusty-cat 不内置数据库。你可以在自己的数据库里保存:
- 业务文件 ID。
- 本地路径。
- OSS
bucket、region、object_key。 - 传输方向:upload / download。
- 分片大小。
- 传输状态和进度。
- 凭证引用:例如
credential_ref。
不要保存:
access_key_secret原文。- 可以长期访问资源的敏感 URL。
- 未脱敏的调试日志。
进程重启后,读取未完成任务,重新构造 AliOssDirectUpload 或 AliOssDirectDownload,再调用 try_enqueue(...) 或 enqueue_and_wait(...)。
10. 常见问题排查
| 现象 | 常见原因 | 处理建议 |
|---|---|---|
返回 403 |
AccessKey 错误、权限不足、Region 错误、机器时间偏差。 | 检查 Bucket、Region、RAM 权限、本机时间。 |
| 上传后对象不可见 | multipart complete 失败或任务未真正完成。 | 看 complete callback 和错误日志,不要只看分片上传成功。 |
| 下载无法获取文件大小 | HEAD 请求权限不足或签名失败。 |
检查读取权限和 OSS 对象 URL。 |
| 分片反复重试 | 网络不稳定、chunk_size 不合适、OSS 限流。 | 调整 chunk_size,降低并发,查看 OSS 服务端日志。 |
| 程序退出后任务状态丢失 | 业务没有持久化任务状态。 | 在进度回调中异步写入自己的数据库。 |
11. 本篇小结
阿里云 OSS 直连模式的优点是后端接入简单、传输链路直接、SDK 能本地处理签名和 multipart 流程。它的前提是运行环境可信,能够安全持有 AccessKey。
如果你的 Rust 程序运行在服务端或内部环境,AliOssDirectUpload 和 AliOssDirectDownload 是很直接的选择。如果程序运行在用户机器上,不要把 Secret 放进去,下一篇的预签名 URL 模式会更合适。