Skip to content

Latest commit

 

History

History

manifest

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

清单格式

清单用于定义 原文件备用 URL 的映射,以及相应的配置参数。例如:

# example
/assets/jquery.js
	https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js
	https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js
	https://unpkg.com/jquery@3.2.1/dist/jquery.min.js
	hash=hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=

空行会被忽略。缩进使用一个或多个空白符。

绝对路径的 URL 以 https:// 开头,本地测试时可使用 http://。请勿使用 // 前缀。

相对路径的 URL 以 / 开头,总是从当前站点根目录计算,避免混乱。

URL 必须规范化,例如空格使用 %20 表示,目录分隔符使用一个 /,无 ../ 上级目录等。

原文件

用于定义需代理的文件,例如上述清单中 /assets/jquery.js

原文件可以是绝对路径 URL,用于覆盖业务中的第三方资源。

备用 URL

用于定义代理的目标。缩进开头。

备用 URL 可以是相对路径,但目前不支持递归到清单中其他原文件。

原文件的 URL 会自动添加到备用 URL 中,作为后备资源。

实际运行时,程序未必按清单中的顺序尝试备用 URL,顺序会受站点权重等因素影响。

注意备用 URL 是否支持 CORS,并非所有免费 CDN 都可使用。

参数

用于定义资源解码时的操作。缩进开头。使用 key=value 格式。例如:

/foo.js
	https://img.foo.com/xx.png
	https://img.bar.com/yy.png
	pos=1000
	xor=123

对于这两个备用 URL,程序都会跳过前 1000 字节数据,并对内容进行 xor 计算。

完整参数可参考 params.md

如果只想对某个 URL 设置参数,可将参数定义在 URL 的片段部分。例如:

/foo.js
	https://img.foo.com/xx.png#pos=1000&xor=123
	https://mycdn.com/foo.js

URL 片段中的参数具有最高优先级,可覆盖外部定义的参数。

文件标记

原文件可以没有备用 URL 和参数,例如:

/assets/img.jpg

/assets/img.jpg.webp

/assets/img.jpg.avif

这种情况仅用于标记文件存在,例如 图片渐进 的场合会用到。

原文件的 URL Query

原文件的 URL 无需携带 Query。程序查询清单时,会忽略 URL 请求中的 Query。例如:

/foo.js
	...

无论请求 /foo.js?v=1 还是 /foo.js?v=2,都会命中 /foo.js 文件。

如果原文件 URL 存在 Query,那么 URL 必须完全相等才会命中。例如:

/getfile.php?name=bar.js
	...

只有请求 /getfile.php?name=bar.js 才会命中。

目录匹配

原文件以 / 结尾可匹配目录。程序会将原文件的后缀部分,拼接到备用 URL 后面。例如:

/api/
	https://api.mysite.com/

访问 /api/path/to?a=1 代理到 https://api.mysite.com/path/to?a=1

目录匹配可实现批量代理,而不必预先配置每个文件的备用 URL,更简单更灵活。但不可设置 hash 参数,安全性略低。

代理时会保留 method、body 数据,但请求头需通过 req_headers 参数保留,响应头需通过 headers 保留,状态码需通过 valid_status 保留。备用 URL 推荐使用子域名,从而能通过根域 cookie 携带登录态。

注意,一次请求可能会访问多个备用 URL。因此对于动态接口,后端必须有防重放机制。同时设置 stream=off 禁用流模式,防止每个 URL 内容不一致,导致内容错乱。

配置

配置以 @ 开头,用于定义一些参数。参考下文。

覆盖

如果出现同样的文件名、配置名,后出现的将会覆盖已存在的。这个机制在清单外链时会用到。

权重配置

使用 @weight 可配置站点的初始权重值,数字越大优先级最高。例如:

@weight
	cdnjs.cloudflare.com=100
	cdn.jsdelivr.net=60

程序会优先使用 cdnjs 站点的备用 URL。

@weight 后面添加地区信息,可为不同地区的用户使用不同的权重:

@weight zh-cn
	lib.baomitu.com=100
	cdn.jsdelivr.net=50
	ajax.googleapis.com=0

这样可根据实际情况,为不同地区的用户分配更合理的站点。

地区信息目前使用 navigator.language 属性,小写值。

地区中有 - 的时候,例如 en-us,程序会优先使用 @weight en-us;没有则尝试 @weight en,最后尝试 @weight。如果都没有,则使用程序内置的 默认权重

站点参数

使用 @host 可配置备用站点的公共参数。例如:

/file1
	https://foo.com/file1#k1=v1
	https://bar.com/file1

/file2
	https://foo.com/file2#k1=v1
	https://bar.com/file2

/file3
	https://foo.com/file3#k1=v1
	https://bar.com/file3

这里每个 foo.com 的 URL 都有 k1=v1 配置,显然很累赘。这时可用 @host 统一配置:

@host foo.com
	k1=v1

/file1
	https://foo.com/file1
	https://bar.com/file1

/file2
	https://foo.com/file2
	https://bar.com/file2

/file3
	https://foo.com/file3
	https://bar.com/file3

这样 foo.com 站点的备用 URL 默认带有 k1=v1 配置。

常用案例

# 访问自己 CDN 时携带完整 referrer,便于分析
@host cdn.mysite.com
	referrer_policy=unsafe-url

# 访问图床站点时,自动跳过前 1000 字节的图片外壳
@host i.imgur.com
	pos=1000

全局参数

使用 @global 可定义全局参数。例如:

@global
	open_timeout=2s

所有备用 URL 都会继承该参数。

参数优先级

总结下各类参数的优先级(从低到高):

系统预设参数 < 全局参数 < 站点参数 < 文件参数 < URL 片段参数

外部清单

使用 @include 可配置外部清单 URL 列表。例如:

@include
	https://foo/manifest-1.conf
	https://bar/manifest-2.conf

freecdn 会依次加载它们,扩充到当前清单结尾。

将完整的清单存储在免费 CDN 上,可减少入口清单的体积,从而节省你的站点流量。

目前不支持多层嵌套,即外部清单不支持 @include

清单 URL 可以是当前清单中的原文件,例如:

/manifest-full
	https://site-1/manifest-v1
	https://site-2/manifest-v1
	https://img-host/20201210.gif#pos=50
	hash=xxxxx

@include
	/manifest-full

程序将从 site-1、site-2、img-host 加载完整清单,如果都失败,最后尝试当前站点 /manifest-full 文件,从而提高稳定性。配合 Hash 参数,还可防止外部清单被篡改,从而提高安全性。

有了这个机制,无论资源数量有多少,你站点下的清单只需存储几个 URL 和 Hash,通常只有几百字节,进一步降低流量开销。

优化建议

为了避免很小的改动导致用户重新下载完整清单,你可以将小改动放在一个补丁清单里。因为同名的文件配置,后出现的会覆盖已存在的,所以完整清单里的旧配置会被后面的补丁清单覆盖:

/manifest-full
	https://site-1/2020-10
	https://site-2/2020-10
	hash=xxxxx

/manifest-patch
	https://site-1/2020-10-15_18-05-01
	https://site-2/2020-10-15_18-05-01
	hash=xxxxx

@include
	/manifest-full
	/manifest-patch

小变更累积在 /manifest-patch 对应的 URL 里,这样用户只需下载较小的文件;完整清单的 URL 保持不变,用户仍从缓存中获取。这样即使频繁更新,用户也不会消耗很多流量。

当补丁文件变得较大时,再重新生成完整清单,清空补丁文件。

对于存在大量文件并且更新频繁的站点,使用该方案可节省不少流量。当然,如果 CDN 流量是免费的话,就没必要这么麻烦了。

更新参数

使用 @update 配置更新参数。清单有两种更新方式:定期轮询 和 消息推送。

定期轮询

freecdn 每隔一段时间访问 /freecdn-manifest.txt,检查清单是否有变化。时间间隔通过 interval 参数设置,格式为 时间单位,例如:

@update
	interval=100s

如果参数未指定,默认为 300s。

消息推送

相比轮询,消息推送实时性更高。

freecdn 使用 WebSocket 和更新服务器保持长连接,当服务器检测到站点清单有变化时,会通知所有在线用户;用户收到通知后,重新加载清单文件,从而快速生效。

更新服务器的 URL 通过 services 参数设置。可设置多个,使用空格间隔,例如:

@update
	services=wss://foo.com wss://bar.com

你可以使用公共服务,或者 搭建自己的服务

即使开启消息推送,清单仍会定期轮询,确保推送服务不稳定的情况下仍能更新,提升稳定性。

备用地址

通过 backup 参数可指定清单的备用地址,多个使用空白符分隔:

@update
	backup=url1 url2 ...

如果程序从当前站点获取清单失败,则依次从备用地址获取,使网站具备离线更新的能力。

清单签名

清单必须存在签名才能在离线模式下使用。

签名位于清单最后行,以 # SIGN: 开头:

...
# SIGN: $sign-base64

签名算法为 ECDSA SHA-256,使用 Base64 编码,共 88 字符(二进制 64 字节)。实际使用时可通过 freecdn manifest --sign 对清单进行签名。

公钥硬编码在 loader-js 中,防止被恶意脚本篡改。通过 freecdn js --make 创建的脚本已自动填入公钥。

私钥由开发者保管,可通过 freecdn key 查看。