跳转到内容

接入服务端导出

AelionSDK 不包含托管渲染服务。Remote Export 是一组适配接口:SDK 负责固定 Project、生成内容 ID、管理幂等和 Job;你的代码负责鉴权、服务端任务、素材绑定和结果地址。

启动时 SDK 会准备:

  • aelion.remote-export/1.0.0 协议握手和服务端预算;
  • canonical 的冻结 Project manifest;
  • 选中的 profile ID;
  • content ID 和 idempotency key;
  • content-addressed Asset 清单及握手成功后签发的逐素材短期授权;
  • 当前任务的 AbortSignal;
  • Authorizer 返回的短期授权。

Project 里的 Asset locator 应是稳定业务 key。服务端根据 key 和用户权限获取原片,不信任客户端传来的临时 URL。

import type { RemoteExportAuthorizer } from '@aelionsdk/export';
const authorizer: RemoteExportAuthorizer = {
async authorize(signal) {
const token = await getShortLivedExportToken(signal);
return {
scheme: 'Bearer',
token: token.value,
expiresAtMs: token.expiresAtMs,
};
},
};

Token 只在本次运行中使用,不会写入 Project、content ID 或默认日志。服务端应限制 token 的用户、项目、素材和用途,并让有效期覆盖任务启动阶段。

import type { RemoteExportProvider } from '@aelionsdk/export';
const provider: RemoteExportProvider = {
id: 'my-render-service',
async negotiate(request, authorization, signal) {
return api.negotiateRender(request, authorization, signal);
},
async start(request, authorization, signal) {
const response = await api.startRender(request, authorization, signal);
return {
providerJobId: response.jobId,
events: api.watchRender(response.jobId, signal),
cancel: reason => api.cancelRender(response.jobId, reason),
cleanup: reason => api.cleanupRender(response.jobId, reason),
};
},
};

negotiate() 必须在上传素材前返回共同协议版本、可接受的 profile 和单素材字节上限。 SDK 会先拒绝版本/profile/预算不兼容,再请求素材 token,避免把原片上传给注定无法执行的 Provider。

api.watchRender() 返回异步事件流。Progress 必须单调前进,completed 只能出现一次。完成结果里的 providerJobIdcontentIdprofileId 必须与请求对应;SDK 会拒绝串任务或被篡改的结果。

const job = session.export.startRemote({
profile: 'mp4-h264-aac',
provider,
authorizer,
assets: [
{
assetId: 'camera-original',
contentId: sourceContentId,
byteLength: sourceBytes,
sha256: sourceSha256,
locator: { type: 'business-key', key: 'camera-original' },
},
],
assetAuthorizer: {
authorizeAsset: (asset, signal) => issueAssetReadToken(asset.assetId, signal),
},
onProgress: (value, stage) => {
remoteTaskStore.update({ progress: value, stage });
},
});
try {
const result = await job;
console.log(result.outputUrl, result.outputToken);
} catch (error) {
showRemoteExportError(error);
}

默认 manifest 来自当前冻结 Project。只有服务协议确实需要额外 JSON 绑定时才传 manifest。默认 idempotency key 按内容生成,重复点击或网络重试应落到同一个服务端任务;除非对接已有协议,不要自己随意覆盖。

完成事件还必须返回输出 sha256byteLength。下载端要同时验证二者;素材授权和 output token 都不能写回 Project、canonical manifest、遥测或持久日志。

  1. 验证用户、租户、Project、Asset 和 profile 权限;
  2. 对 manifest 重新执行输入预算、Schema 和引用校验;
  3. 根据稳定 Asset key 获取 original,不能信任客户端 URL;
  4. 校验 Material 版本、完整性和服务端执行许可;
  5. 按 idempotency key 返回已有任务,避免重复计费和重复文件;
  6. 支持取消、过期和半成品清理;
  7. 用短期 output URL 或一次性 token 交付结果;
  8. 记录 contentId、Project revision、profile、SDK/服务端引擎版本和 diagnostic。

把 Provider Job ID、content ID 和业务任务 ID保存在服务端或本地任务记录。重新打开页面后,应用可以通过自己的 API 查询任务和结果;当前 Session Job 对象本身不能跨刷新序列化。

取消请求也要幂等:用户可能在浏览器、任务中心和自动超时路径中多次取消同一个任务。

保持本地预览与服务端成片一致

Section titled “保持本地预览与服务端成片一致”

服务端不是把浏览器 UI 复刻一遍。它需要实现兼容的 Project、Render IR、Material 和字体/素材解析,并固定引擎版本。遇到未知版本或不支持的 Material 时应明确失败,不能静默忽略效果。

本地和远程的选择策略见选择导出格式,鉴权和日志要求见安全与部署清单