SU.RUN 对外提供统一的存储服务接入能力。本页用于说明控制台准备项、最小验证步骤、授权接入方式与上线前检查要点,适合正式项目在早期建立稳定的接入基线。
本文档适用于第一次接入 SU.RUN 的团队,也适用于已经具备存储服务接入经验、但需要统一接入方式、权限边界与业务结构的项目。内容覆盖控制台准备、最小验证、授权链接、安全约束和上线清单,可直接作为第一版实施路径。
如后续还需补充前端直传、AI 训练、素材归档或自定义域名访问,可在最小链路验证完成后,再继续查阅 SDK 示例、接口说明和 AI 环境接入说明。
这是 SDK 与业务服务端连接存储服务的入口,可理解为平台提供的标准访问地址。上传、下载、列目录和签名计算都会基于它进行。
这是一组长期凭证,默认只应保存在业务服务端、任务机或受控容器中。正式项目不建议将其直接下发给浏览器、移动端或第三方插件。
存储桶决定资源归属,文件路径决定业务结构。稳定的桶名和前缀规划,比单纯把文件传上去更重要,因为后续审计、生命周期和 AI 工作流都会依赖这套结构。
这是浏览器直传、临时下载和第三方受控接入最常用的能力。业务服务端先使用长期密钥生成短时有效的 URL,再交给客户端使用。
下面两处是接入初期最常用的控制台位置,分别用于准备访问密钥与创建测试存储桶。
在控制台的访问密钥页面记录访问密钥 ID、访问密钥,并复制当前组织可用的接入域名。这组参数会作为后续 SDK、脚本和业务系统的统一入口。
建议不要一开始就接正式业务。先创建一个测试存储桶,完成一次上传、列目录、下载和删除,确认密钥权限、网络连通性和文件路径规划都正确。
当最小验证稳定后,再把存储能力接到图片、视频、素材库、训练数据或知识库业务里。这样排查时更容易区分是存储问题还是业务代码问题。
生产环境建议仅在服务端持有访问密钥。前端上传通过服务端签发临时授权或授权链接,避免将长期密钥直接暴露给浏览器或 App。
无论使用 Node.js、Python、Go 还是后续的 AI 容器,建议都先把接入参数收口到环境变量。这样后续迁移环境、切换密钥或排查问题时,成本会低很多。
SURUN_S3_ENDPOINT=https://your-s3-endpoint SURUN_ACCESS_KEY_ID=your-access-key SURUN_SECRET_ACCESS_KEY=your-secret-key SURUN_DEFAULT_BUCKET=media-assets
import {
S3Client,
PutObjectCommand,
ListObjectsV2Command,
GetObjectCommand,
DeleteObjectCommand,
} from '@aws-sdk/client-s3';
const client = new S3Client({
region: 'auto',
endpoint: process.env.SURUN_S3_ENDPOINT,
credentials: {
accessKeyId: process.env.SURUN_ACCESS_KEY_ID!,
secretAccessKey: process.env.SURUN_SECRET_ACCESS_KEY!,
},
});
export async function runHealthCheck() {
await client.send(
new PutObjectCommand({
Bucket: process.env.SURUN_DEFAULT_BUCKET!,
Key: 'test/health-check.txt',
Body: 'ok',
ContentType: 'text/plain',
}),
);
await client.send(
new ListObjectsV2Command({
Bucket: process.env.SURUN_DEFAULT_BUCKET!,
Prefix: 'test/',
}),
);
await client.send(
new GetObjectCommand({
Bucket: process.env.SURUN_DEFAULT_BUCKET!,
Key: 'test/health-check.txt',
}),
);
await client.send(
new DeleteObjectCommand({
Bucket: process.env.SURUN_DEFAULT_BUCKET!,
Key: 'test/health-check.txt',
}),
);
}import os
import boto3
client = boto3.client(
's3',
endpoint_url=os.environ['SURUN_S3_ENDPOINT'],
aws_access_key_id=os.environ['SURUN_ACCESS_KEY_ID'],
aws_secret_access_key=os.environ['SURUN_SECRET_ACCESS_KEY'],
region_name='auto',
)
bucket = os.environ['SURUN_DEFAULT_BUCKET']
key = 'test/health-check.txt'
client.put_object(
Bucket=bucket,
Key=key,
Body=b'ok',
ContentType='text/plain',
)
client.list_objects_v2(Bucket=bucket, Prefix='test/')
client.get_object(Bucket=bucket, Key=key)
client.delete_object(Bucket=bucket, Key=key)1. 使用控制台提供的接入域名初始化 S3 客户端 2. 用访问密钥 ID / 访问密钥连接测试存储桶 3. 上传一个小文件到 test/health-check.txt 4. 列出 test/ 前缀,确认文件可见 5. 下载该文件并校验内容 6. 删除测试文件,确认清理完成
此阶段不接业务接口,仅使用最小 SDK 代码确认接入域名、访问密钥 ID、访问密钥和测试存储桶均可用。
const client = new S3Client({
region: 'auto',
endpoint: process.env.SURUN_S3_ENDPOINT,
credentials: {
accessKeyId: process.env.SURUN_ACCESS_KEY_ID!,
secretAccessKey: process.env.SURUN_SECRET_ACCESS_KEY!,
},
});建议固定使用一个明确的健康检查路径,例如 test/health-check.txt,后续所有环境都用同一套检查口径。
await client.send(
new PutObjectCommand({
Bucket: process.env.SURUN_DEFAULT_BUCKET!,
Key: 'test/health-check.txt',
Body: 'ok',
ContentType: 'text/plain',
}),
);上传完成后再继续验证列目录、读取和删除,不要只测上传成功。正式项目最容易遗漏的就是“能写不能读”或“能读不能删”的权限差异。
await client.send(
new ListObjectsV2Command({
Bucket: process.env.SURUN_DEFAULT_BUCKET!,
Prefix: 'test/',
}),
);
await client.send(
new GetObjectCommand({
Bucket: process.env.SURUN_DEFAULT_BUCKET!,
Key: 'test/health-check.txt',
}),
);
await client.send(
new DeleteObjectCommand({
Bucket: process.env.SURUN_DEFAULT_BUCKET!,
Key: 'test/health-check.txt',
}),
);前端直传文件时,先由业务服务端签发上传地址,再由浏览器把文件传到存储服务。
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
const client = new S3Client({
region: 'auto',
endpoint: process.env.SURUN_S3_ENDPOINT,
credentials: {
accessKeyId: process.env.SURUN_ACCESS_KEY_ID!,
secretAccessKey: process.env.SURUN_SECRET_ACCESS_KEY!,
},
});
export async function createUploadUrl() {
const command = new PutObjectCommand({
Bucket: 'media-assets',
Key: 'uploads/2026/06/avatar.png',
ContentType: 'image/png',
});
return getSignedUrl(client, command, { expiresIn: 600 });
}下载时同样由服务端生成短时可用地址,避免把长期凭证下发给客户端。
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
const client = new S3Client({
region: 'auto',
endpoint: process.env.SURUN_S3_ENDPOINT,
credentials: {
accessKeyId: process.env.SURUN_ACCESS_KEY_ID!,
secretAccessKey: process.env.SURUN_SECRET_ACCESS_KEY!,
},
});
export async function createDownloadUrl() {
const command = new GetObjectCommand({
Bucket: 'media-assets',
Key: 'projects/2026/06/cover.png',
});
return getSignedUrl(client, command, { expiresIn: 300 });
}测试阶段若将长期密钥直接放入前端或临时脚本,虽然能够快速完成上传验证,但正式项目进入真实用户环境后会带来明显的权限失控风险。浏览器一旦获得长期密钥,任何人都可能绕过业务服务端,直接写入、覆盖或读取不应暴露的文件路径。
推荐做法是由业务服务端持有长期密钥,并根据业务身份、桶名、文件路径、文件类型和过期时间生成授权 URL。这样前端只获取一次性的上传或下载地址,权限可控、日志可追溯,后续审计、风控和问题排查也更清晰。
优先检查接入域名是否填写正确、服务端网络是否可达,以及环境变量是否真的被当前运行进程读取。
通常需要检查访问密钥 ID 与访问密钥是否配对错误、SDK endpoint 是否写错、bucket 名称是否误填,或者请求头与签名时使用的参数不一致。
优先确认 Bucket 和 Prefix 是否一致,另外检查你上传时的对象路径是否和读取时使用的前缀完全匹配。
这往往不是存储本身问题,而是业务系统加入了新的对象路径、权限判断、文件类型限制或下载授权逻辑。建议用 requestId 把最小验证日志和业务日志串起来看。
因为上传成功不等于接入安全。正式上线时,浏览器和 App 不应保存长期密钥,授权链接用于将权限边界收回到业务服务端。
建议一定先建。测试桶可以帮你把网络、权限、对象路径规划和 SDK 初始化问题提前暴露,避免一开始就污染正式数据。
建议至少包含环境、业务线和日期,例如 prod/user-uploads/2026/06/。这样后续做归档、生命周期、审计和迁移都会轻松很多。
文档中心帮助你完成接入,客户服务页帮助你了解采购、支持与服务信息。