Skip to main content
状态:已构建,尚未部署 / 未接入 kira-cdn。 该 API 已在代码中实现,但服务尚未上线,调用方(kira-cdn)也还未改造。当前线上变体路径仍是 imgproxy。详见 kira-image 概述
kira-image 是内部专用服务,无公网入口。所有调用走 Fly 6PN 私网 kira-image.internal:8083,并以共享密钥 X-Internal-Key 鉴权(kira-cdn → kira-image)。共两个端点:
方法路径鉴权说明
GET/health健康检查
POST/v1/ensureX-Internal-Key确保变体存在并返回 URL

GET /health

curl http://kira-image.internal:8083/health
# → ok
返回纯文本 ok,供 Fly 做实例存活探测。

POST /v1/ensure

给定一个源图和一组变体规格,对每个规格:
  1. (源标识 ‖ 规范化变换 ‖ 格式) 算出确定性变体 key;
  2. HEAD R2 检查是否已存在;
  3. 若任一变体缺失,则仅抓取一次源图,对缺失项生成并以公开对象写入 R2;
  4. 返回每个规格名对应的公开 cdn.kira.art URL。

鉴权

请求头必须携带与服务端 KIRA_IMAGE_INTERNAL_KEY 完全相同的值:
X-Internal-Key: $KIRA_IMAGE_INTERNAL_KEY
缺失或不匹配返回 401 Unauthorized

请求体

{
  // 二选一:从 R2 直接按 key 读,或从外部 URL 抓取
  "source": { "key": "u/U/thread/T/asset.png" },   // 或 { "url": "https://…" }
  "specs": [
    {
      "name": "thumb",          // 必填:本变体在响应里的标识
      "width": 400,             // 默认 0 = 该轴不约束
      "height": 0,              // 默认 0 = 该轴不约束
      "quality": 80,            // 可选;JPEG 默认 80 / WebP 默认 75
      "format": "webp",         // 可选;webp|jpeg|jpg|png,默认 webp(avif 会降级为 webp)
      "resizingType": "fit",    // 可选;fit(默认)| fill | auto
      "enlarge": false,         // 可选;默认 false(不放大小图)
      "blur": null,             // 可选;高斯模糊 sigma(> 0 生效)
      "maxBytes": null,         // 可选;设置后对质量做二分搜索以装入预算
      "resampling": "lanczos3"  // 可选;lanczos3(默认)| lanczos2 | cubic | linear | nearest
    }
  ]
}
字段名是 camelCaseresizingTypemaxBytes),由 serde rename_all = "camelCase" 决定。source 必须含 keyurl 之一,否则返回 400;两者都缺时无法定位源图。

spec 字段

字段类型默认说明
namestring(必填)响应 variants map 的 key
widthuint0目标宽度;0 = 该轴不约束
heightuint0目标高度;0 = 该轴不约束
qualityuint8?JPEG 80 / WebP 75编码质量;未提供时用服务端默认
formatstring?webpwebp / jpeg / jpg / png;公开 URL 是单一烘焙格式,无 Accept 协商
resizingTypestring?fitfit=装入框、fill=覆盖后居中裁剪、auto=keying 区分但缩放同 fit
enlargeboolfalse是否允许放大小于目标框的源图
blurfloat?null高斯模糊 sigma,> 0 才应用
maxBytesuint?null输出字节预算;设置后在 [10, quality] 内二分搜索最高可用质量
resamplingstring?lanczos3重采样滤波器;计入变体 key(见概述备注)

响应

200 OK,body 是 { "variants": { 规格名: 公开URL } }
{
  "variants": {
    "thumb":   "https://cdn.kira.art/img/ab/cd/<blake3_hash>.webp",
    "preview": "https://cdn.kira.art/img/ef/01/<blake3_hash>.webp"
  }
}

示例

curl -X POST http://kira-image.internal:8083/v1/ensure \
  -H "Content-Type: application/json" \
  -H "X-Internal-Key: $KIRA_IMAGE_INTERNAL_KEY" \
  -d '{
    "source": { "key": "u/U/thread/T/asset.png" },
    "specs": [
      { "name": "thumb",   "width": 400,  "quality": 80, "format": "webp" },
      { "name": "preview", "width": 1024, "quality": 85, "format": "webp" }
    ]
  }'
// 200 OK
{
  "variants": {
    "thumb":   "https://cdn.kira.art/img/3a/9f/3a9f….webp",
    "preview": "https://cdn.kira.art/img/7c/12/7c12….webp"
  }
}

幂等性

变体 key 是 (源标识 ‖ 规范化变换 ‖ 格式) 的 keyed-hash,因此相同源 + 相同规格 ⇒ 相同 key ⇒ 同一个 R2 对象。重复 ensure 同一组变体时:
  • 命中(对象已存在):只做一次 R2 HEAD,根本不抓取源图、不重新编码,直接返回 URL。
  • 部分缺失:只抓取一次源图,仅对缺失项生成。
这正是它能在稳态下极致缩容的原因——变体一旦存在,后续请求几乎零成本,且公开 URL 永不变化(不会冲掉 Cloudflare 缓存)。

错误码

状态码触发条件
400 Bad Requestsource 既无 key 也无 url
401 UnauthorizedX-Internal-Key 缺失或不匹配
422 Unprocessable Entity图片处理失败(如源图超过 KIRA_IMAGE_MAX_SRC_PIXELS、解码失败)
502 Bad Gateway源图抓取失败,或 R2 写入失败
503 Service Unavailable并发信号量获取失败
504 Gateway Timeout单图处理超过 KIRA_IMAGE_PROCESS_TIMEOUT_SECS(默认 30s)
当请求 avif 时,输出会降级为 WebP,服务用真实格式重算 store key,返回的 URL 因此以 .webp 结尾、指向真正写入的字节。