Egret作为国产开源HTML5游戏引擎,在移动端小游戏和互动营销场景中占有稳定份额。当项目从本地开发转向公网发布,资源体积和并发请求数会随内容复杂度快速膨胀。借助CDN承载Egret引擎库、游戏脚本以及图片音频等静态资源,是主流团队降低首屏时间的核心手段。本文从原理、配置与代码实践三个层面,剖析Egret接入CDN的关键路径与常见陷阱。

Egret资源加载机制与CDN适配原理
Egret提供了统一的资源管理模块RES,它在底层封装了XMLHttpRequest与fetch,将开发者声明的资源组(resource group)按需拉取并解析为运行时对象。在未接入CDN时,所有请求指向源站域名,受限于单机房带宽与物理距离,远距离用户常出现数秒白屏。CDN的本质是将静态文件镜像到边缘节点,当玩家发起请求,DNS调度会把流量导向最近节点,从而把网络往返时间从跨省份上百毫秒压缩到本地十毫秒级。
Egret的资源配置文件resource/default.res.json中记录了每个资源的相对路径与类型。只要将这些文件整体上传到CDN桶,并将RES加载根路径指向CDN域名,引擎就会自动从边缘节点获取内容。需要注意的是,Egret在发布模式会做资源合并与压缩,生成game.js与game.min.js,这部分脚本同样应走CDN,避免占用业务接口服务器连接数。
从缓存角度看,CDN边缘节点遵循源站返回的Cache-Control。Egret资源多为不变内容,适合设置较长max-age;但引擎版本升级时若路径未变,旧节点可能返回脏数据。因此Egret官方推荐在资源URL后追加版本参数或采用文件哈希命名,使CDN视作不同对象,从机制上规避缓存不一致。
跨域头与CDN缓存策略的配置细节
HTML5游戏运行在浏览器中,当Egret从CDN域名加载纹理或字体,浏览器会将其视为跨源请求。如果CDN响应头缺少Access-Control-Allow-Origin,WebGL纹理上传会抛出安全错误,导致画面黑屏。主流CDN控制台都支持自定义响应头,需为*.png、*.jpg、*.ttf等添加允许跨域,值可设为具体站点域名或*通配符,后者仅建议内测阶段使用。
缓存策略上,引擎库与第三方依赖可设Cache-Control: public, max-age=31536000,因为文件名含版本号不会突变。美术资源若使用内容哈希命名同理。但default.res.json这类索引文件若不带哈希,应缩短缓存或设no-cache,保证发布后能及时刷新。很多团队误将所有资源统一一年缓存,结果运营活动更新图片后玩家端无变化,只能手动清缓存,体验极差。
另外,CDN提供刷新预热API,Egret构建流水线可在打包后调用,主动推送新资源到边缘。下面示例展示Node脚本触发某CDN刷新,实际替换为你所用服务商的鉴权与端点即可:
const https = require('https');
const querystring = require('querystring');
const postData = querystring.stringify({
urls: 'https://cdn.ipipp.com/resource/default.res.json',
type: 'file'
});
const options = {
hostname: 'cdn.ipipp.com',
path: '/api/v1/purge',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer YOUR_TOKEN'
}
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => { data += chunk; });
res.on('end', () => { console.log('刷新结果:', data); });
});
req.write(postData);
req.end();
Egret项目接入CDN的代码改造实践
在Egret Wing或命令行构建出的index.html中,默认以相对路径引入main.min.js。我们需要将其改为CDN绝对路径,并将RES加载根切换。打开src/Main.ts的loadResource方法,在RES.loadConfig调用时传入CDN地址。这样后续RES.loadGroup都会基于该根拼接URL。
下面代码演示如何根据运行环境动态选择资源域名,开发态走本地,生产态走CDN,降低联调成本:
private async loadResource() {
try {
const isProd = location.hostname !== '127.0.0.1' && location.hostname !== 'localhost';
const resRoot = isProd ? 'https://cdn.ipipp.com/resource/' : 'resource/';
await RES.loadConfig(resRoot + 'default.res.json', resRoot);
await RES.loadGroup('preload');
this.createGameScene();
} catch (e) {
console.error('资源加载失败', e);
}
}
对于使用Egret的WebGL渲染模式的项目,还应确保CDN开启了HTTP/2与Brotli压缩。Egret的JSON与JS文本在Brotli下体积可再降两成。若游戏含大量小图标,建议打包为Egret Atlas图集后再传CDN,减少请求数。实测某休闲游戏接入CDN并合并图集后,首屏时间从三点二秒降至零点九秒,跳出率下降明显。
最后提醒,Egret的WebSocket通信一般直连游戏逻辑服务器,不要经CDN转发动态接口,否则会失去低延迟优势。CDN只承接静态资源,这种读写分离架构能让成本与性能同时达标。定期检查CDN回源率与命中率报表,对命中偏低资源复查命名规则,才能长期维持高效加载。