把网站部署到微信小程序云开发的静态托管上之后,很多人第一件事就是关心资源会不会被外站盗链。图片、视频这类大流量资源一旦被别人直接嵌到他的页面里,消耗的都是你自己的CDN流量。云开发静态托管提供了基于Referer的访问控制能力,配合腾讯云的API,我们可以自己动手写一个小工具,实现防盗链规则的批量管理。这篇文章就从原理到代码,完整地走一遍这个流程。

一、理解云开发静态托管的Referer防盗链原理
所谓Referer防盗链,是指HTTP请求头中的Referer字段会被CDN节点检查。浏览器发起请求时,会自动带上来源页面的地址,CDN拿到这个地址后,与你预设的规则做匹配:如果在白名单里,正常返回资源;如果命中黑名单,或者白名单模式下Referer不在名单内,就拒绝请求,返回403状态码。
云开发的静态托管底层依托腾讯云CDN,所以它的防盗链配置本质上就是CDN层面的Referer黑白名单设置。在腾讯云侧,对应的配置项叫WebAccessControl,通过ModifyWebAccessControl这个接口可以修改。配置里有几个关键字段需要理解清楚:
- accessControlType:控制类型,0表示关闭防盗链,1表示黑名单模式,2表示白名单模式。
- refererType:是否允许空Referer。有些用户直接在地址栏输入URL访问,此时请求头里没有Referer字段,你需要决定这种请求是放行还是拦截。
- refererList:具体名单内容,一行一个域名,支持通配符。
这里有一个容易踩的坑:白名单模式下如果禁止空Referer,用户第一次直接打开你的页面时,页面里的资源请求是会带Referer的,一般没问题;但某些安全软件、浏览器插件会剥掉Referer头,导致资源加载失败。所以建议在不确定的情况下,先允许空Referer观察几天日志,再决定是否收紧策略。
二、准备开发环境与API调用凭据
要开发配置工具,首先需要能调用腾讯云API的凭据。登录腾讯云控制台,进入访问管理,创建一个子账号,只授予云开发相关权限,比如QcloudTCBFullAccess,如果只想管理静态托管,可以进一步收窄到静态托管相关的操作权限。然后为这个子账号生成SecretId和SecretKey,妥善保存。
接着初始化一个Node.js项目,安装官方SDK:
mkdir referer-guard && cd referer-guard npm init -y npm install tencentcloud-sdk-nodejs dotenv
SDK安装好之后,先写一个最小化调用测试连通性。云开发静态托管相关的接口在tencentcloud-sdk-nodejs的tcb包里:
const tencentcloud = require("tencentcloud-sdk-nodejs");
const TcbClient = tencentcloud.tcb.v20180608.Client;
const client = new TcbClient({
credential: {
secretId: process.env.TENCENT_SECRET_ID,
secretKey: process.env.TENCENT_SECRET_KEY,
},
region: "ap-shanghai",
profile: {
httpProfile: {
endpoint: "tcb.tencentcloudapi.com",
},
},
});
// 查询静态托管任务列表,验证凭据是否可用
client.DescribeStaticStorage({ EnvId: "your-env-id" }).then(
(res) => console.log(JSON.stringify(res, null, 2)),
(err) => console.error("调用失败:", err.message)
);把SecretId和SecretKey写在项目根目录的.env文件里,用dotenv加载,避免硬编码进代码。如果这一步能正常返回环境信息,说明凭据和权限都没问题,可以往下走了。
三、开发防盗链配置工具的核心功能
核心功能就是封装ModifyWebAccessControl接口,实现防盗链规则的读取、设置。先看设置白名单的实现:
// referer-guard/lib/control.js
async function setRefererRule(client, envId, options) {
const params = {
EnvId: envId,
Domain: options.domain,
AccessControl: {
AccessControlType: options.type, // 0关闭 1黑名单 2白名单
RefererType: options.allowEmpty ? "all" : "match",
RefererList: options.referers,
},
};
return await client.ModifyWebAccessControl(params);
}
module.exports = { setRefererRule };RefererList是一个数组,每个元素是域名或带通配符的路径,例如"*.example.ipipp.com"。RefererType为all表示允许空Referer,match表示不允许。然后写一个命令行入口,用简单的参数解析就够了,不必引入commander这种重依赖:
// referer-guard/index.js
require("dotenv").config();
const tencentcloud = require("tencentcloud-sdk-nodejs");
const { setRefererRule } = require("./lib/control");
const args = process.argv.slice(2);
function getArg(name) {
const i = args.indexOf("--" + name);
return i > -1 ? args[i + 1] : null;
}
(async () => {
const envId = getArg("env");
const domain = getArg("domain");
const action = getArg("action"); // on / off
const referers = getArg("list") ? getArg("list").split(",") : [];
const TcbClient = tencentcloud.tcb.v20180608.Client;
const client = new TcbClient({
credential: {
secretId: process.env.TENCENT_SECRET_ID,
secretKey: process.env.TENCENT_SECRET_KEY,
},
region: "ap-shanghai",
profile: { httpProfile: { endpoint: "tcb.tencentcloudapi.com" } },
});
if (action === "on") {
if (!domain || referers.length === 0) {
console.error("缺少参数:--domain 与 --list 必填");
process.exit(1);
}
const res = await setRefererRule(client, envId, {
domain,
type: 2, // 白名单模式
allowEmpty: getArg("allow-empty") === "true",
referers,
});
console.log("防盗链已开启:", JSON.stringify(res));
} else if (action === "off") {
const res = await setRefererRule(client, envId, {
domain,
type: 0,
allowEmpty: true,
referers: [],
});
console.log("防盗链已关闭:", JSON.stringify(res));
} else {
console.log("用法:node index.js --env 环境ID --action on --domain 你的域名 --list 域名1,域名2");
}
})();使用方式很直观,比如开启白名单并允许空Referer:
node index.js --env cloud1-xxx --action on \ --domain static.example.ipipp.com \ --list "static.example.ipipp.com,*.example.ipipp.com" \ --allow-empty true
这里注意Windows用户在命令行里不需要写续行符,直接写成一整行即可,路径相关参数里的反斜杠也要原样保留。另外建议在写代码时对Referer格式做一层校验,比如用正则判断是否是合法域名,避免把误输入的字符串提交到API后规则全部失效。
四、常见问题与注意事项
第一个常见问题是配置生效延迟。防盗链规则修改后,CDN节点需要一点时间刷新配置,通常几分钟内生效,不要因为改完立刻测试没反应就反复提交。第二个问题是开启白名单后忘了把自己的域名加进去,导致自己站点的资源全部403,这也是新手最容易犯的错误,配置前务必核对名单内容。
第二个问题是HTTPS页面引用HTTP资源时,部分浏览器出于安全策略不发送Referer,如果你的站点同时有HTTPS和HTTP版本,规则要考虑周全。必要时可以给域名名单同时加上http和https两种前缀的匹配项,或者干脆允许空Referer兜底。
最后要提醒的是,Referer防盗链并不是绝对安全的方案,Referer头本身是可以伪造的,专业盗链者可以轻易绕过。如果对资源保护要求高,可以在这个工具的基础上继续扩展,比如结合URL签名(带时效的鉴权链接)、IP访问限频等手段,多层防护叠加使用效果更好。这个命令行工具的结构已经为后续扩展留好了空间,加一个签名URL生成模块就能集成进来。