ESC 关闭 Ctrl+K 打开

如何做好一个随机图片api

如何做好一个快速,高清,稳定的随机图片api
如何做好一个随机图片api

随机图片api是什么

随机图片 API 是一种可以返回随机图片的接口,通常用于网站的背景图头像等。

一个随机图 API,每次请求都返回不同的图片。从流程上来说,需要有一个图片库,然后通过 API 端点随机返回其中一张图片。

一个最简单的,最直接的架构如下

或者返回 URL,图片资源托管在其他地方:

鉴于国内高昂的带宽成本,第一种直接返回图片的方式 在实际应用中并不常见,更多时候是使用第二种方式——将图片存储在 CDN 或对象存储中,然后通过 API 返回图片的 URL,客户端再通过 URL 去获取图片。同时直接返回方式的随机抽取逻辑和图片读取逻辑都在服务器端,对于大图片库来说,会消耗较多的服务器 CPU 和带宽资源。

那么这就是我们引入第二个问题:如何保证 API 的快速、高清、稳定?

现有图片API分析

多个API测试结果

随机图片 API 在网络上已经有很多成熟实现和开源项目,简直是浩如烟海,有站点记录一些随机图 API 的地址 =w=

我们来小小测试一下,浅浅测试几个 API,各测试 22 次,间隔 1 秒,去掉最高最低取平均,汇总如下:

API总耗时 (ms)302 耗时 (ms)图片耗时 (ms)平均大小 (KB)平均分辨率网络稳定性
栗次元775.75361.79412.68544.361786 x 1041 ~ 8000 x 4464腾讯云 EdgeOne文件大小/分辨率波动极大
LoliAPI924.69375.62547.74734.51920 x 1080 ~ 7680 x 4320腾讯云 EdgeOne分辨率集中在 1920x1080,大小波动中等
樱花API3306.73直接返回无3023306.73908.411920 x 1080 ~ 2048 x 1152新浪图片 + 百度直接返回,速度慢
夜轻 Blog981.58294.47687.101588.681228 x 868 ~ 9000 x 5039腾讯云 EdgeOne302 较快,但图片体积大,格式混杂
本站API716.61214.98501.63614.732455 x 1706 ~ 4659 x 2160腾讯云 EdgeOne / 阿里云 ESA 混合302 最快,AVIF 格式
东方Project1076.81323.04753.77164.341200 x 804 ~ 4000 x 3000日本东京单服务器直连WebP 格式
点击查看 栗次元 22次原始测试数据
次数总耗时 (ms)302 耗时 (ms)图片耗时 (ms)格式大小 (KB)分辨率
1981.23432.20549.02webp1529.784936 x 2515
2674.35388.14286.21webp173.692008 x 1080
3796.11366.39429.72webp120.102000 x 1178
4689.48408.41281.07webp356.013840 x 2160
5803.04399.46403.58webp794.844608 x 2592
6721.35339.07382.28webp245.942560 x 1440
7654.65357.60297.05webp194.154096 x 2658
8666.20327.46338.75webp672.063800 x 2136
9634.71340.83293.88webp232.822560 x 1809
10817.93326.90491.03webp464.442480 x 1754
11746.79343.15403.64webp802.895760 x 3240
12630.67331.89298.78webp245.942560 x 1440
13681.07365.64315.43webp329.473265 x 1837
14719.51395.35324.17webp346.534495 x 1041
15728.98363.30365.68webp106.492500 x 1548
16702.79375.55327.24webp566.393075 x 2048
171419.38378.181041.20webp1349.944000 x 2667
18722.48341.03381.45webp435.624608 x 3072
191361.95337.251024.70webp4093.513840 x 2160
20784.11321.10463.01webp1235.908000 x 4464
21914.97347.89567.09webp654.523949 x 2170
22713.36402.40310.96webp136.211786 x 1248
平均(去高低)775.75361.79412.68-544.36-
点击查看 LoliAPI 22次原始测试数据
次数总耗时 (ms)302 耗时 (ms)图片耗时 (ms)格式大小 (KB)分辨率
1921.38378.70542.68webp694.361920 x 1080
21027.19348.96678.23webp513.471920 x 1080
3675.71355.77319.94webp523.201920 x 1080
4698.66368.88329.78webp158.053000 x 1815
5917.37343.50573.87webp137.842367 x 1540
6728.38368.14360.23webp679.461920 x 1080
7941.48384.27557.21webp1626.537680 x 4320
81032.88392.63640.26webp1060.732048 x 1152
9816.60369.54447.05webp333.143600 x 2100
10788.42350.10438.32webp1176.203763 x 1972
11775.60397.94377.66webp645.021920 x 1080
12819.66426.31393.35webp627.721920 x 1080
13919.94397.50522.44webp275.501920 x 1200
14967.21384.03583.18webp519.841920 x 1080
151845.19367.751477.44webp3698.944800 x 2700
16926.40407.22519.18webp425.942048 x 1152
171306.89371.49935.40webp4321.093800 x 2193
181769.44384.441385.00webp311.361920 x 1200
19955.23406.15549.07webp376.651920 x 1080
20811.14333.21477.93webp358.031920 x 1080
21681.64371.02310.62webp259.901920 x 1080
22688.38364.29324.09webp425.962800 x 1680
平均(去高低)924.69375.62547.74-734.5-
点击查看 樱花API 22次原始测试数据
次数总耗时 (ms)302 耗时 (ms)图片耗时 (ms)格式大小 (KB)分辨率
12169.880.002169.88jpg528.611920 x 1080
22427.120.002427.12jpg969.021920 x 1080
42440.280.002440.28jpg996.061920 x 1080
52455.690.002455.69jpg844.581920 x 1080
62617.610.002617.61jpg972.441920 x 1080
71985.790.001985.79jpg716.331920 x 1080
82009.120.002009.12jpg643.611920 x 1080
92532.530.002532.53jpg1202.271920 x 1080
101774.980.001774.98jpg442.602048 x 1152
1112864.040.0012864.04jpg1505.491920 x 1080
122089.210.002089.21jpg805.051920 x 1080
138964.690.008964.69jpg1238.412048 x 1152
141873.940.001873.94jpg370.741920 x 1080
152386.170.002386.17jpg716.362048 x 1152
161569.790.001569.79jpg1208.701920 x 1080
175893.840.005893.84jpg711.351920 x 1080
183627.940.003627.94jpg1713.322048 x 1152
192559.840.002559.84jpg996.061920 x 1080
2010340.630.0010340.63jpg1193.501920 x 1080
212611.450.002611.45jpg1198.522048 x 1152
222067.250.002067.25jpg256.991920 x 1080
平均(去高低)3306.730.03306.73-908.41-
点击查看 夜轻 Blog 22次原始测试数据
次数总耗时 (ms)302 耗时 (ms)图片耗时 (ms)格式大小 (KB)分辨率
1984.98295.50689.49jpg507.141920 x 1080
2986.73296.02690.71jpg1214.924552 x 2560
3948.57284.57664.00jpg1479.032560 x 1440
4901.43270.43631.00webp1030.743675 x 2160
5916.08274.82641.26jpg1139.309000 x 5039
61525.26457.581067.68jpg4534.133000 x 1753
7784.15235.24548.90jpg908.653500 x 2475
8966.04289.81676.23jpg1201.542560 x 1440
9901.77270.53631.24jpg992.942560 x 1553
101259.40377.82881.58jpg2963.493440 x 1440
111786.97536.091250.88png6059.664000 x 2250
12778.98233.70545.29jpg521.862560 x 1282
131055.70316.71738.99png2174.521756 x 1239
14934.82280.45654.37jpg1185.003508 x 2480
15805.22241.57563.65jpg1214.924552 x 2560
16710.57213.17497.40jpg521.862560 x 1282
17688.55206.57481.99jpg343.471228 x 868
181193.69358.11835.58jpg2923.503508 x 2480
191171.85351.55820.29jpg2616.584439 x 2392
20908.22272.47635.76jpg1417.733300 x 1856
21673.85202.15471.69jpg447.211786 x 1248
221209.49362.85846.64png2778.563200 x 1800
平均(去高低)981.58294.47687.10-1588.68-
点击查看 本站API 22次原始测试数据
次数总耗时 (ms)302 耗时 (ms)图片耗时 (ms)格式大小 (KB)分辨率
1883.37265.01618.36avif746.683728 x 2160
2638.16191.45446.71avif332.663210 x 1812
3751.17225.35525.82avif475.592560 x 1440
4751.52225.46526.07avif718.163055 x 2160
5753.27225.98527.29avif592.233840 x 2160
6677.78203.33474.45avif442.023632 x 2160
7942.02282.61659.41avif368.962877 x 2160
8847.60254.28593.32avif517.212880 x 2160
9624.76187.43437.33avif307.162811 x 2160
10770.82231.24539.57avif846.452788 x 1782
11621.16186.35434.82avif895.712591 x 2160
12724.33217.30507.03avif444.403580 x 2160
13844.85253.46591.40avif386.963049 x 2160
14831.29249.39581.90avif372.702455 x 1706
15674.02202.21471.81avif653.753556 x 2000
16622.62186.79435.84avif382.882756 x 2036
17607.81182.34425.47avif908.793438 x 2160
18647.08194.12452.96avif1007.102880 x 2160
19657.89197.37460.53avif1021.044659 x 2160
20758.91227.67531.24avif776.083840 x 2160
21643.75193.12450.62avif680.233283 x 2160
22580.97174.29406.68avif746.132932 x 1694
平均(去高低)716.61214.98501.63-614.73-
点击查看 东方Project 22次原始测试数据
次数总耗时 (ms)302 耗时 (ms)图片耗时 (ms)格式大小 (KB)分辨率
11039.05311.71727.33webp93.241583 x 1117
21110.60333.18777.42webp189.932143 x 999
31122.66336.80785.86webp186.641800 x 1525
41006.19301.86704.33webp79.641400 x 885
51111.17333.35777.82webp179.812000 x 2000
61051.61315.48736.13webp168.861600 x 1200
71204.79361.44843.35webp561.932850 x 2000
81071.14321.34749.80webp137.111411 x 1000
91057.06317.12739.94webp111.181600 x 1131
101053.82316.15737.67webp132.991600 x 1200
111069.40320.82748.58webp211.683500 x 2458
121130.39339.12791.27webp128.861500 x 1100
131035.21310.56724.65webp131.661200 x 1200
144008.751202.632806.13webp616.953600 x 2242
15985.16295.55689.61webp53.541600 x 1200
161134.10340.23793.87webp112.521318 x 1040
17974.56292.37682.19webp82.401200 x 804
181092.27327.68764.59webp219.264000 x 3000
191102.21330.66771.54webp119.371350 x 750
201119.08335.73783.36webp220.923508 x 2480
211005.16301.55703.61webp104.162000 x 1414
221035.19310.56724.63webp114.701600 x 1200
平均(去高低)1076.81323.04753.77-164.34-

从数据可以看出:

  • 本站API 总耗时平均约 717 ms速度最快,302 响应仅 215 ms(所有 API 中最快),格式统一为 AVIF
  • 栗次元 总耗时平均约 776 ms,速度第二,但文件大小和分辨率波动极大
  • 东方Project 总耗时平均约 1077 ms,302 中等(323 ms),但图片加载较慢(754 ms),格式统一为 WebP,平均体积仅 164 KB(所有 API 中最小),但第 14 次异常缓慢(4 秒),应该是跨境网络问题
  • LoliAPI 总耗时平均约 925 ms,速度中等,分辨率集中在 1920 x 1080
  • 夜轻 Blog 总耗时平均约 982 ms,302 响应较快(294 ms),但图片加载慢(687 ms),且平均体积高达 1.59 MB,格式混杂(jpg / webp / png)
  • 樱花API 总耗时平均约 3307 ms,速度慢且极不稳定(1 次超时,多次 3~12 秒),直接返回 jpg 导致服务器带宽压力大

发现使用 302 跳转方式的 API 显著优于直接返回类,因为上述几个 API 的 302 通常由部署在 CDN 边缘的 Pages / Workers 完成,响应时间极短,到用户的网络延迟最低。虽然图片资源也要回源才能加载,但整体延迟仍然较低。

更何况使用直接返回方式的 API 还是用的 世界上最好的语言 PHP,从请求到返回图片不知道要几十次用户态拷贝,不慢就怪了。

那么,这些延迟数字背后有没有理论支撑?用户到底能接受多久的等待?我查证了一下 HCI 领域的延迟感知研究,整理如下:

延迟等级评估

等级总延迟用户感知行为影响依据(已核实)
极速300–600 ms即时,无等待感满意度最高Nielsen 1993:<1s 用户思路不中断(网页通用阈值,最近似参照)
良好600 ms–1.2 s轻微感知,流畅注意力未被打断Nah 2004:Web 对象容忍上限约 2 s;此区间在容忍范围内
可接受1.2–2 s明显等待感开始分心,但不放弃Nah 2004:2 s 是可容忍等待上限;Ramsay et al. 1998:延迟影响页面感知质量
偏慢2–4 s明显挫败感移动端放弃率上升Google/SOASTA 2017:>3 s 跳出率 53%;Ramsay 1998:延迟越长页面越被视为无趣
很慢4–8 s认为出错/崩溃大量放弃,信任受损Nielsen 1993:>10 s 用户离开(工程估算:此区间已触发放弃行为)
不可用>8 s视为服务崩溃几乎全部放弃Nielsen 1993 10 s 极限;需 fallback,否则违反基本可用性原则

已核实来源

  • Ramsay, Barbesi & Preece (1998)Interacting with Computers, 10(1), 77–86. doi.org/10.1016/S0953-5438(97)00019-2 · 测试 2 s–数十秒延迟对用户页面感知的影响,含图片资源延迟。
  • Nah, F.F.H. (2004)Behaviour and Information Technology, 23(3), 153–163. doi.org/10.1080/01449290410001669914 · Web 对象可容忍等待时间约 2 s。
  • Nielsen, J. (1993)Usability Engineering, Academic Press. 0.1 s / 1 s / 10 s 三级响应时间阈值,HCI 基准。无 DOI(书籍)。
  • Google/SOASTA (2017) — “The State of Online Retail Performance.” 行业报告,非学术论文。thinkwithgoogle.com

重要说明

  • 以上论文研究对象均为网页整体加载,不存在专门针对”随机图片 API 端到端延迟”的学术论文。本表延迟数值由真实 302 跳转链路物理计算 + 上述研究的用户感知阈值推导而来,非直接引用数据。在正式文档中引用时,建议注明”参考自 Nah 2004 / Ramsay 1998,结合工程测量估算”。

最终方案

根据以上数据和研究:

直接返回的架构虽然理论上一次请求复用连接,但是随机和静态资源返回都在一个服务器上,一旦 QPS 大于 10,在国内这个带宽比金子还贵的情况下,想必不那么经济。

有没有不吃经济的打法呢?还是边缘函数(Pages / Workers)又快又好,稳定性还高,总不可能阿里云腾讯云的服务器都同时挂掉吧。虽然比直接返回的架构多出来一次跨域握手耗时(其实这个也可以通过路径代理解决),但是各个方面还是更好滴。

那么问题来了,具体该怎么设计呢?

首先我们应该知道一个好的图片 API 应该做到什么:当然是清晰快速稳定。那么为了实现这三个目标,我们需要尽可能把请求在边缘节点就处理了,这样可以减少网络延迟,提高响应速度。图片资源虽然需要源站对象存储,但是可以开启 CDN 的缓存,也能从边缘节点获取,这样就大大减少了网络延迟。同时我们还需要尽可能压缩图片大小,但是又不能损失太多画质——那么就该请出一个神奇的图片格式:AVIF

图片格式对比

格式压缩类型透明动画相对大小浏览器支持编码速度最佳场景
JPG有损100%100%极快兼容旧浏览器
WebP有损 / 无损~60%97%+照片 / API 首选
PNG无损~300%100%中等图标 / 截图
AVIF有损 / 无损~45%~93%慢(5–20× WebP预生成图库

随机图片 API 推荐策略

既然图片库是静态的,最佳做法是预生成 AVIF 后直接返回:

  • 同质量下体积只有 JPG 的 40–50%,WebP 的 70%
  • 解码速度接近 WebP,现代浏览器支持率已达 93%+
  • 边缘节点只负责 302 跳转,零实时转码压力

分辨率选择

同时还有个问题,上述测试 API 有的图片返回十几个 MB、8K 分辨率,这是完全没有必要的——都 2026 年了,1080p 的图片虽然不能满足要求,我们的 API 还是应该尽量返回 2K 以上的图片。但太高了除了浪费带宽以外毫无用处,综上所述,返回 2K–4K 分辨率的 AVIF 格式图片 是最经济且效果最好的打法。

推荐架构

边缘 Pages 函数负责 302 跳转,图片资源放在 nginx 静态站点并套 CDN,整体链路如下:

各层职责

层级组件职责
接入层边缘 Pages Functions接收 API 请求,从预生成列表随机选择,返回 302
逻辑层image-list.ts构建时生成,运行时只读,避免文件系统访问
存储层nginx 静态站点 + CDN托管 AVIF 图片,边缘缓存,就近返回

为什么这样设计

  • 302 在边缘完成:用户到边缘节点的 RTT 最低,随机选择逻辑只消耗几 KB 内存和几 ms CPU
  • 图片走 CDN:AVIF 预生成后静态托管,CDN 边缘缓存命中率极高,图片加载时间和带宽成本都最低
  • 零实时转码:所有格式转换在构建时完成,运行时零压力
  • 可扩展:新增分类只需在 config.ts 添加路径映射,重新构建部署即可

成功上线

基于以上的架构描述,我自己写了一个随机图片 API 喵。

仓库

adokiu
/
RamdomPicAPI
-
-
-
-

API 地址

境内使用 ESA / EdgeOne 混合加速,境外使用 Cloudflare 加速。

预览效果

Doki 初音未来随机图

如何做好一个随机图片api

https://dokiu.example.com/blog/image-api-design/
作者
Dokiu
发布于
许可协议
CC BY-NC-SA 4.0

评论区

评论加载中...