跳到主要内容

eo版壁纸api

最后更新于:

腾讯云 EdgeOne 边缘函数实现七牛云 & S3 存储随机图床 API

img

腾讯云 EdgeOne 边缘函数实现七牛云 & S3 存储随机图床 API

版权

次文章来源@十三的《腾讯云 EdgeOne 边缘函数实现七牛云 & S3 存储随机图床 API》文章。感谢大佬的文章❤️❤️❤️。

记录于2026年7月14日。

1 序言 🖼️

个人静态博客存在壁纸分层展示需求,PC 端宽屏壁纸、移动端竖屏壁纸需要两套独立图库,前端直连对象存储存在多重业务痛点:

  • 统一图库混存图片,随机接口返回图片比例与设备不匹配,页面展示效果差;
  • 前端直接请求存储域名触发 CORS 跨域拦截,同时持续消耗源站下行流量,抬高存储计费;
  • 对象存储真实域名、AK / SK 鉴权密钥暴露客户端,存在文件盗刷、资源泄露风险。

依托腾讯云 EdgeOne 边缘函数搭建代理中间层,边缘节点直出图片二进制流,天然实现 PC / 移动端 图库物理隔离、边缘缓存降费、统一跨域处理、全链路异常兜底,无需后端服务即可完成可落地随机图床 API。


2 业务需求与方案选型对比

2.1 项目约束

  • 资源分离:PC、移动端图片池使用独立存储目录,通过请求路由自动绑定对应图库,前端无需额外传参区分设备;
  • 跨域解决:前端页面直接调用接口,无需在存储侧配置 CORS,兼容 fetch、axios 等主流请求库;
  • 缓存降费:边缘节点缓存图片二进制资源,减少七牛云 / S3 源站回源请求与下行流量;
  • 异常容错:目录无图片、存储鉴权失败、网络超时、资源 404 场景自动返回兜底占位图,避免页面空白报错。

2.2 两种实现方案三线对比

对比维度302 重定向方案EdgeOne 边缘节点代理直出图片流
流量链路用户 → 边缘节点 → 302 跳转 → 对象存储源站用户 → 就近边缘节点,边缘回源存储拉取图片,二进制流直接返回客户端
缓存能力仅缓存 302 响应头,图片本体无法缓存完整缓存图片二进制数据,同区域重复访问无源站流量
密钥安全前端可捕获存储 CDN 域名,AK / SK 存在泄露盗刷风险密钥存放边缘环境变量,前端无法感知存储地址与鉴权信息
跨域运维每个存储桶单独配置 CORS,多存储场景运维繁琐边缘统一输出跨域响应头,一套规则适配全部 S3 兼容存储
异常降级资源失效直接返回 404,无兜底展示逻辑边缘捕获全链路异常,自动切换预设兜底图片返回
长期成本源站下行流量持续消耗,存储计费偏高边缘缓存命中占比提升后,源站流量成本大幅下降

2.3 方案选型结论

优先选用 EdgeOne 边缘节点代理直出图片流 架构。 该方案在存储安全、流量成本、运维复杂度、异常容错四大维度全面优于 302 重定向,适配静态博客、轻量化站点高频调用随机图床接口的长期运营场景,零后端架构大幅降低服务器运维成本。


3 整体架构与运行链路

3.1 完整请求链路流程图文字说明

/api 路由

/m-api 路由

请求异常/目录无图

用户浏览器

EdgeOne全球边缘节点

路由匹配判断

读取PC图库目录 blog/bg/

读取移动端图库目录 blog/bg-m/

携带鉴权签名请求存储获取图片列表

随机选取单张图片资源

边缘回源拉取图片二进制流

追加跨域、缓存响应头

边缘本地缓存图片

加载兜底默认图片

+−↺⛶

  • 用户发起 /api/m-api 接口请求,流量调度至就近 EdgeOne 边缘节点;
  • 边缘函数匹配请求路由绑定对应资源目录,携带鉴权签名调用存储文件列表接口;
  • 过滤图片格式后随机选取资源,边缘节点回源拉取图片二进制;
  • 统一拼接跨域、长缓存响应头,图片流返回客户端并在边缘本地缓存;
  • 链路任意环节触发异常时,自动加载兜底图片返回,保障页面正常渲染。

3.2 资源分层规则

  • PC 端图库目录:blog/bg/,存放 16:9 / 21:9 宽屏高清壁纸,适配桌面端展示;
  • 移动端图库目录:blog/bg-m/,存放 9:16 竖屏壁纸,适配手机、平板竖屏场景;
  • 两套目录物理隔离,接口路由自动绑定对应目录,前端无需传递设备标识参数。

4 获取七牛云密钥(兼容标准 S3 存储)

  • 七牛云密钥获取流程
    • 登录七牛云控制台,进入个人中心 - 密钥管理页面;
    • 复制 AccessKey(AK)SecretKey(SK) 两组鉴权密钥;
    • 记录存储空间名称、CDN 访问域名、线上兜底图片完整地址。
  • S3 通用存储适配说明 阿里云 OSS、腾讯云 COS、MinIO 等标准 S3 对象存储仅需重写签名生成函数、替换存储列表请求域名,边缘代理整体业务逻辑无需改动。 img

⚠️ 关键避坑警告:生产环境严禁将 AK、SK 密钥硬编码写入边缘函数源码,必须通过 EdgeOne 环境变量配置密钥,防止源码泄露导致存储文件被盗刷、产生高额流量账单。


5 腾讯 EdgeOne 边缘函数

5.1 添加触发边缘函数的域名

  • 进入 EdgeOne 控制台站点管理,接入业务域名并完成 DNS 解析生效;
  • 域名配置,加速域名:api.img.你的备案域名.com
  • 回源配置,IP 域名:119.29.29.29
  • 回源配置,回源 HOST 头:api.img.你的备案域名.com
  • 不使用模板,下一步解析 DNS 就可以
  • 配置 SSL 证书,开启全站 HTTPS 强制跳转,关闭 HTTP 明文访问;
  • 开启域名边缘函数执行权限,限制流量直接回源源站。 img

5.2 创建边缘函数

  • 侧边栏选择边缘函数,新建函数,运行环境选择 创建 Hello World img
  • 函数名称:api-img
  • 描述:随机图床 API
  • 函数代码:全部删除,填写函数代码,先空着创建部署也可以。 img

5.3 编辑函数代码(核心)

  • 完整边缘函数源码
  • AK 密钥、SK 密钥
  • BUCKET 存储桶名称,例如 sinc-img
  • DOMAIN,最好填写套一层 CDN 的,EO的域名img.你的备案域名.com
  • PC_PREFIX 电脑壁纸存储路径,例如 “blog/bg/”
  • MOBILE_PREFIX 手机端壁纸存储路径,例如 “blog/bg-m/”
  • 所以,你上传电脑壁纸和手机壁纸,就分别传这俩路径就可以 img
 1/** * 随机图 API - 腾讯云 EdgeOne 大满贯版 * 特性:直连七牛云目录、极速内存缓存、边缘代理(零跨域、非302) */
 2// ==========================================// 1. 核心配置区// ==========================================const CONFIG = {  AK: "AK密钥",  SK: "SK密钥",  BUCKET: "七牛云存储空间名称",  DOMAIN: "最好填写套一层CDN的,EO的域名", // 你的图床 CDN 域名
 3  PC_PREFIX: "blog/bg/",  MOBILE_PREFIX: "blog/bg-m/"};
 4// ==========================================// 2. 全局内存缓存// ==========================================let pcImages = [];let mobileImages = [];let lastCheckTime = 0;const CACHE_TTL = 3 * 60 * 1000; // 3 分钟缓存
 5addEventListener('fetch', event => {  event.respondWith(handleRequest(event.request))});
 6// ==========================================// 3. 密码学:生成七牛云鉴权 Token// ==========================================async function generateQiniuToken(path) {  const signingStr = `${path}\n`;  const encoder = new TextEncoder();  const key = await crypto.subtle.importKey(    'raw', encoder.encode(CONFIG.SK),    { name: 'HMAC', hash: 'SHA-1' }, false, ['sign']  );  const signature = await crypto.subtle.sign('HMAC', key, encoder.encode(signingStr));  const base64 = btoa(String.fromCharCode(...new Uint8Array(signature)));  const encodedSign = base64.replace(/\+/g, '-').replace(/\//g, '_');  return `QBox ${CONFIG.AK}:${encodedSign}`;}
 7// ==========================================// 4. 抓取七牛云真实文件列表// ==========================================async function fetchImagesFromQiniu(prefix) {  try {    const apiPath = `/list?bucket=${CONFIG.BUCKET}&prefix=${prefix}&limit=1000`;    const apiHost = 'rsf.qiniuapi.com';    const token = await generateQiniuToken(apiPath);
 8    const response = await fetch(`https://${apiHost}${apiPath}`, {      headers: {        'Authorization': token,        'Content-Type': 'application/x-www-form-urlencoded'      }    });
 9    if (!response.ok) return [];
10    const data = await response.json();    if (!data.items) return [];
11    return data.items      .filter(item => item.mimeType && item.mimeType.startsWith('image/'))      .map(item => `${CONFIG.DOMAIN}/${item.key}`);
12  } catch (error) {    console.error(`拉取目录 ${prefix} 失败:`, error);    return [];  }}
13// ==========================================// 5. 代理获取图片并注入跨域头 (核心新增逻辑)// ==========================================async function proxyImage(imageUrl) {  try {    // 边缘节点出面去你的 CDN 拿图    const response = await fetch(imageUrl, {      headers: {        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) EdgeOne-Proxy"      }    });
14    if (response.ok) {      // 拿到图片后,重写响应头,强行允许跨域      const newHeaders = new Headers(response.headers);      newHeaders.set("Access-Control-Allow-Origin", "*");      newHeaders.set("Cache-Control", "no-cache"); // 告诉浏览器不要缓存当前API链接,以免下次拿不到新图
15      // 返回 200 状态码和真实图片数据流      return new Response(response.body, {        status: 200,        headers: newHeaders      });    }
16    // 如果图片代理失败,降级回 302 重定向    return Response.redirect(imageUrl, 302);  } catch (e) {    // 网络异常,降级回 302 重定向    return Response.redirect(imageUrl, 302);  }}
17// ==========================================// 6. 主路由逻辑// ==========================================async function handleRequest(request) {  const url = new URL(request.url);  const route = url.pathname;
18  // 初始化或更新缓存  if (Date.now() - lastCheckTime > CACHE_TTL || pcImages.length === 0 || mobileImages.length === 0) {    try {      const [newPc, newMobile] = await Promise.all([        fetchImagesFromQiniu(CONFIG.PC_PREFIX),        fetchImagesFromQiniu(CONFIG.MOBILE_PREFIX)      ]);
19      if (newPc.length > 0) pcImages = newPc;      if (newMobile.length > 0) mobileImages = newMobile;      lastCheckTime = Date.now();    } catch (e) {      console.error("更新列表失败,暂时使用旧缓存");    }  }
20  // --- 处理电脑壁纸 ---  if (route === '/api') {    if (pcImages.length === 0) return new Response("初始化中...", {status: 503});    const randomImg = pcImages[Math.floor(Math.random() * pcImages.length)];    // 调用代理函数,直接返回图片流    return await proxyImage(randomImg);  }
21  // --- 处理手机壁纸 ---  if (route === '/m-api') {    if (mobileImages.length === 0) return new Response("初始化中...", {status: 503});    const randomImg = mobileImages[Math.floor(Math.random() * mobileImages.length)];    // 调用代理函数,直接返回图片流    return await proxyImage(randomImg);  }
22  return new Response("API 正常运行。电脑壁纸请访问 /api,手机壁纸请访问 /m-api", {    status: 200,    headers: { "Content-Type": "text/html;charset=UTF-8" }  });}

展开

5.4 新增触发规则

  • 函数发布完成后进入触发规则管理页面,新增自定义匹配规则;
  • 匹配路径配置:^/api.*^/m-api.*,匹配域名选择已接入业务站点域名api.img.你的备案域名.com
  • 保存规则,等待 2 ~ 5 min 完成全网边缘节点配置同步。 img img

6 全维度功能测试验证

6.1 基础访问测试

  • 请求 https://api.img.你的备案域名.com/api,多次刷新随机返回 PC 宽屏壁纸二进制图片; img
  • 请求 https://api.img.你的备案域名.com/m-api,随机返回移动端竖屏适配图片; img
  • 非法路由如 /test 访问,接口返回 404 文本提示,路由匹配逻辑正常。

6.2 缓存机制测试

  • 浏览器开发者工具查看响应头,携带 Cache-Control: public,max-age=86400 缓存标识;
  • 同一区域重复访问同一张图片,EdgeOne 边缘节点命中本地缓存,无额外存储回源请求;
  • 高频调用场景下,持续削减七牛云 / S3 对象存储下行流量,长期降低存储计费成本。

6.3 跨域测试

  • 前端页面通过 fetch、axios 直接调用接口,浏览器无 CORS 跨域拦截报错;
  • OPTIONS 预检请求返回 204 状态码,完整携带跨域允许头,兼容各类前端请求场景。

6.4 异常降级测试

  • 目标图库目录未上传任何图片,接口自动返回配置兜底占位图;
  • 存储 AK / SK 配置错误、存储接口网络超时,捕获异常后切换兜底图片;
  • 存储 CDN 域名失效、图片资源被删除,统一走降级逻辑,页面无空白崩溃。

7 当前代码现存缺陷 & 可落地迭代优化方案

7.1 现有代码局限

  • 内存单实例缓存短板:EdgeOne 边缘单实例内存缓存不持久,节点扩容、实例重启后缓存数据清空,无分布式持久化缓存支撑;
  • 图片数量上限约束:七牛 list 接口单次限制返回 1000 条文件,图库图片总量超过 1000 张时无法全量随机抽取;
  • 缺少图片尺寸过滤逻辑:仅通过文件后缀筛选资源,无法根据宽高比例筛选适配图片;
  • 无接口限流防护:未增加 IP 访问频次限制,恶意高频刷接口会持续消耗存储回源流量;
  • 日志体系简陋:仅基础控制台打印错误信息,无结构化日志上报,无法统计缓存命中率、接口访问量。

7.2 落地迭代优化方案

  • 接入 EdgeOne KV 分布式缓存,将文件列表持久化缓存,减少重复请求存储列表接口;
  • 递归分页拉取存储文件列表,突破单轮 1000 条文件上限,支持上万张图库全量随机;
  • 扩展接口传参能力,支持前端传入宽高比例参数,过滤对应尺寸图片资源;
  • 基于客户端 IP + KV 存储实现分钟级限流,拦截恶意高频刷接口行为;
  • 对接 EdgeOne 日志服务,结构化记录缓存命中、回源失败、访问频次等运营数据;
  • 增加动态缓存时长参数,前端可按需传入 max-age 控制边缘缓存有效期;
  • 抽离签名逻辑,兼容七牛、COSOSS、MinIO 多类 S3 标准存储一键切换。

8 全文总结

8.1 方案适用场景

  • Hexo / VitePress 等纯静态博客、个人 / 企业静态站点,需要随机封面、随机壁纸 API;
  • 业务需要 PC、移动端两套完全隔离的图片资源池,区分设备展示不同尺寸图片;
  • 无后端服务器,希望依靠边缘计算实现轻量图片接口,降低服务器运维成本;
  • 希望隐藏对象存储真实域名,减少源站流量消耗,控制存储服务计费。

8.2 整体工程优势

  • 零后端服务部署,仅依赖 EdgeOne 边缘函数,服务器运维成本几乎为 0;
  • 全球边缘节点分发图片资源,图片加载速度优于前端直连对象存储;
  • 鉴权密钥存放边缘环境变量,前端无法获取存储地址与鉴权信息,数据安全性更高;
  • 统一封装跨域、缓存、异常降级逻辑,一套代码兼容全部 S3 标准对象存储;
  • 完整工程闭环:业务需求 → 方案对比 → 架构设计 → 源码拆解 → 部署实操 → 全维度测试 → 迭代优化,所有代码配置可直接复现落地。

Created with ❤️ by 十三

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!

分享打赏

腾讯云 EdgeOne 边缘函数实现七牛云 & S3 存储随机图床 API

https://blog.nw177.cn/posts/40-博客搭建/07-腾讯云-edgeone-边缘函数实现七牛s3-随机图床-api/

作者

十三

发布于

2026-07-13

许可协议

CC BY-NC-SA 4.0

最新文章

文档导航