Skip to content

Commit 65dfc5f

Browse files
committed
优化CDN缓存配置,提升性能;支持设置管理端删除、拉黑等操作绕过缓存,实时生效,见readme3.1.3.9节
1 parent d508694 commit 65dfc5f

31 files changed

+102
-27
lines changed

README.md

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848

4949
此外,上传**并没有严格限制文件类型**,理论上你可以上传**任何**文件,但是暂时不会针对图片和视频外的文件进行特殊优化和适配。
5050

51-
![CloudFlare](static/202410011443570.png)
51+
![CloudFlare](static/readme/202410011443570.png)
5252

5353
# 2.Features
5454

@@ -74,7 +74,7 @@
7474
>
7575
> Cloudflare R2渠道:上传大小不限,但超过免费额度会扣费,详见[Pricing | Cloudflare R2 docs](https://developers.cloudflare.com/r2/pricing/)
7676
>
77-
> ![](static/202411052346701.png)
77+
> ![](static/readme/202411052346701.png)
7878
7979
- **上传方式多样**:支持多种上传方式(**拖拽点击、粘贴**)(Web/API)
8080

@@ -153,19 +153,19 @@
153153

154154
1.[@BotFather](https://t.me/BotFather)发送`/newbot`,按照提示输入bot的备注、用户名等信息。成功创建后获得`TG_BOT_TOKEN`
155155

156-
![](static/202409071744569.png)
156+
![](static/readme/202409071744569.png)
157157

158158
2. 创建一个新的频道(Channel),进入新建的频道,选择频道管理,将刚才创建的机器人设为频道管理员。
159159

160-
![](static/202409071758534.png)
160+
![](static/readme/202409071758534.png)
161161

162-
![](static/202409071758796.png)
162+
![](static/readme/202409071758796.png)
163163

164-
![](static/202410291531473.png)
164+
![](static/readme/202410291531473.png)
165165

166166
3.[@VersaToolsBot](https://t.me/VersaToolsBot)**转发**一条第2步新建频道中的消息,获取`TG_CHAT_ID`(频道ID)
167167

168-
![](static/202409071751619.png)
168+
![](static/readme/202409071751619.png)
169169

170170
</details>
171171

@@ -176,15 +176,15 @@
176176

177177
1. 前往Cloudflare Dashboard,选择`R2 存储对象`
178178

179-
![](static/202411052318204.png)
179+
![](static/readme/202411052318204.png)
180180

181181
2. 选择`创建存储桶`,名称随意,填完后点击`创建存储桶`即可完成创建
182182

183-
![](static/202411052319402.png)
183+
![](static/readme/202411052319402.png)
184184

185185
3. 根据需求可选操作:如果**需要启用图像审查,需要开启存储桶的公网访问权限**,有两种开启方式,详见下图。无论你选择哪种方式,都需要记下完整的公网访问链接,格式为`https://xxxx.xxx`
186186

187-
![image-20241105232759131](static/202411052327191.png)
187+
![image-20241105232759131](static/readme/202411052327191.png)
188188

189189
</details>
190190

@@ -221,7 +221,7 @@
221221

222222
2. 打开 Cloudflare Dashboard,进入 Pages 管理页面,选择创建项目,选择`连接到 Git 提供程序`
223223

224-
![1](static/202407201047300.png)
224+
![1](static/readme/202407201047300.png)
225225

226226
3. 按照页面提示输入项目名称,选择需要连接的 git 仓库,点击`部署站点`
227227

@@ -236,21 +236,21 @@
236236
237237
将前面新建的存储桶绑定到项目,名称为`img_r2`
238238

239-
![](static/202411052323183.png)
239+
![](static/readme/202411052323183.png)
240240

241241
如果后续要开启**图像审查**,需要设置`R2PublicUrl`环境变量,值为前面记下的**R2存储桶公网访问链接**
242242

243-
![](static/202411052330663.png)
243+
![](static/readme/202411052330663.png)
244244

245245
</details>
246246

247247
3. **绑定KV数据库**
248248

249249
- 创建一个新的KV数据库
250250

251-
> ![](static/202408261035367.png)
251+
> ![](static/readme/202408261035367.png)
252252
>
253-
> ![](static/202408261037971.png)
253+
> ![](static/readme/202408261037971.png)
254254
255255
- 进入项目对应`设置`->`函数`->`KV 命名空间绑定`->`编辑绑定`->`变量名称`,填写`img_url`,KV命名空间选择刚才创建好的KV数据库
256256

@@ -298,7 +298,7 @@
298298
299299
正常启动,控制台输出如下:
300300

301-
![202408191829163](static/202408191855625.png)
301+
![202408191829163](static/readme/202408191855625.png)
302302

303303
</details>
304304

@@ -394,6 +394,27 @@ Web端在登录页面输入你的**认证码**即可登录使用;API端需要
394394
395395
设置`AllowRandom`环境变量,值为`true`,以从图床中随机获取一张图片,详见[API文档](#4.2.2随机图API)。
396396
397+
#### 3.1.3.9管理端删除、拉黑等操作优化
398+
399+
正常情况下,因为CloudFlare CDN缓存的存在,在管理端进行删除、拉黑、加白名单等操作不会立即生效,需要等到缓存过期才能生效。
400+
401+
**为了让操作立即生效**,请添加`CF_ZONE_ID`、`CF_EMAIL`、`CF_API_KEY`环境变量,获取方式如下:
402+
403+
<details>
404+
<summary>操作详情</summary>
405+
406+
`CF_ZONE_ID`:
407+
408+
![image-20241211123633692](static/readme/20241211123633692.png)
409+
410+
`CF_EMAIL`:即登录CloudFlare账号的邮箱
411+
412+
`CF_API_KEY`:
413+
414+
![image-20241211140019607](static/readme/202412111400766.png)
415+
416+
</details>
417+
397418
##### </details>
398419
399420
### 3.1.4其他操作指南
@@ -404,11 +425,11 @@ Web端在登录页面输入你的**认证码**即可登录使用;API端需要
404425
1. **修改环境变量方式**:
405426
406427
407-
![](static/202408261040233.png)
428+
![](static/readme/202408261040233.png)
408429
409430
**修改环境变量后需要重新部署才能生效!**
410431
411-
![](static/202408261041507.png)
432+
![](static/readme/202408261041507.png)
412433
413434
2. **程序更新方式**:
414435
@@ -417,7 +438,7 @@ Web端在登录页面输入你的**认证码**即可登录使用;API端需要
417438
418439
如果有新的环境变量需要添加,请根据文档要求进行添加,然后重试部署。
419440
420-
![](static/202409161736365.png)
441+
![](static/readme/202409161736365.png)
421442
422443
</details>
423444
@@ -431,9 +452,9 @@ Web端在登录页面输入你的**认证码**即可登录使用;API端需要
431452
432453
## 4.1Web端使用方式
433454
434-
![](static/202412092301397.png)
455+
![](static/readme/202412092301397.png)
435456
436-
![](static/202412092305405.png)
457+
![](static/readme/202412092305405.png)
437458
438459
## 4.2API文档
439460
@@ -537,6 +558,7 @@ Web端在登录页面输入你的**认证码**即可登录使用;API端需要
537558
26. :white_check_mark:~~文件详情增加文件大小记录~~(2024.12.10已完成)
538559
27. :hourglass_flowing_sand:支持管理员自定义全局默认链接前缀
539560
28. :white_check_mark:~~开放更多文件格式~~(2024.12.9已完成)
561+
29. :white_check_mark:~~进行删除、加入白名单、加入黑名单等操作时,自动清除CF CDN缓存,避免延迟生效~~(2024.12.11已完成)
540562
541563
</details>
542564
@@ -551,6 +573,7 @@ Web端在登录页面输入你的**认证码**即可登录使用;API端需要
551573
1. :hourglass_flowing_sand:增加新的图片审查渠道
552574
1. :white_check_mark:~~R2渠道在管理端删除时,存储桶同步删除~~(2024.12.4已修复)
553575
1. :white_check_mark:~~读取文件响应头增加允许跨域头`access-control-allow-origin: *`~~(2024.12.9已修复)
576+
1. :white_check_mark:~~上传界面加入访问限制白名单~~(2024.12.11已修复)
554577
555578
</details>
556579
@@ -568,11 +591,11 @@ Web端在登录页面输入你的**认证码**即可登录使用;API端需要
568591
569592
- PicGo插件设置中搜索`web-uploader`,安装可自定义前缀的版本,如图:
570593
571-
![](static/202408231141491.png)
594+
![](static/readme/202408231141491.png)
572595
573596
- 打开`图床设置`->`自定义Web图床`->`Default`,然后按照下图方式配置,注意API地址和自定义图片URL前缀按照自己的域名进行修改。(**如果设置了`AUTH_CODE`,一定以`?authCode=your_authCode`的方式添加到API地址后面**):
574597
575-
![](static/202408261959174.png)
598+
![](static/readme/202408261959174.png)
576599
577600
- 设置完成,确定即可使用PicGo上传到自建的图床。
578601

functions/api/manage/block/[id].js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ export async function onRequest(context) {
88
next, // used for middleware or to fetch assets
99
data, // arbitrary space for passing data between middlewares
1010
} = context;
11+
// 组装 CDN URL
12+
const url = new URL(request.url);
13+
const cdnUrl = `https://${url.hostname}/file/${params.id}`;
14+
1115
// 解码params.id
1216
params.id = decodeURIComponent(params.id);
1317

@@ -18,6 +22,15 @@ export async function onRequest(context) {
1822
value.metadata.ListType = "Block"
1923
await env.img_url.put(params.id,"",{metadata: value.metadata});
2024
const info = JSON.stringify(value.metadata);
25+
26+
// 清除CDN缓存
27+
const options = {
28+
method: 'POST',
29+
headers: {'Content-Type': 'application/json', 'X-Auth-Email': `${env.CF_EMAIL}`, 'X-Auth-Key': `${env.CF_API_KEY}`},
30+
body: `{"files":["${ cdnUrl }"]}`
31+
};
32+
await fetch(`https://api.cloudflare.com/client/v4/zones/${ env.CF_ZONE_ID }/purge_cache`, options);
33+
2134
return new Response(info);
2235

2336
}

functions/api/manage/delete/[id].js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ export async function onRequest(context) {
88
next, // used for middleware or to fetch assets
99
data, // arbitrary space for passing data between middlewares
1010
} = context;
11+
// 组装 CDN URL
12+
const url = new URL(request.url);
13+
const cdnUrl = `https://${url.hostname}/file/${params.id}`;
14+
1115
// 解码params.id
1216
params.id = decodeURIComponent(params.id);
1317

@@ -22,6 +26,14 @@ export async function onRequest(context) {
2226

2327
await env.img_url.delete(params.id);
2428
const info = JSON.stringify(params.id);
29+
30+
// 清除CDN缓存
31+
const options = {
32+
method: 'POST',
33+
headers: {'Content-Type': 'application/json', 'X-Auth-Email': `${env.CF_EMAIL}`, 'X-Auth-Key': `${env.CF_API_KEY}`},
34+
body: `{"files":["${ cdnUrl }"]}`
35+
};
36+
await fetch(`https://api.cloudflare.com/client/v4/zones/${ env.CF_ZONE_ID }/purge_cache`, options);
2537

2638
return new Response(info);
2739
} catch (e) {

functions/api/manage/white/[id].js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ export async function onRequest(context) {
88
next, // used for middleware or to fetch assets
99
data, // arbitrary space for passing data between middlewares
1010
} = context;
11+
// 组装 CDN URL
12+
const url = new URL(request.url);
13+
const cdnUrl = `https://${url.hostname}/file/${params.id}`;
14+
1115
// 解码params.id
1216
params.id = decodeURIComponent(params.id);
1317

@@ -18,6 +22,15 @@ export async function onRequest(context) {
1822
value.metadata.ListType = "White"
1923
await env.img_url.put(params.id,"",{metadata: value.metadata});
2024
const info = JSON.stringify(value.metadata);
25+
26+
// 清除CDN缓存
27+
const options = {
28+
method: 'POST',
29+
headers: {'Content-Type': 'application/json', 'X-Auth-Email': `${env.CF_EMAIL}`, 'X-Auth-Key': `${env.CF_API_KEY}`},
30+
body: `{"files":["${ cdnUrl }"]}`
31+
};
32+
await fetch(`https://api.cloudflare.com/client/v4/zones/${ env.CF_ZONE_ID }/purge_cache`, options);
33+
2134
return new Response(info);
2235

2336
}

functions/file/[id].js

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,14 @@ export async function onRequest(context) { // Contents of context object
7676
if (fileType) {
7777
headers.set('Content-Type', fileType);
7878
}
79+
// 根据Referer设置CDN缓存策略,如果是从/或/dashboard等访问,则仅允许浏览器缓存;否则设置为public,缓存时间为1年
80+
if (Referer && Referer.includes(url.origin)) {
81+
headers.set('Cache-Control', 'private, max-age=86400');
82+
} else {
83+
headers.set('Cache-Control', 'public, max-age=31536000');
84+
}
7985

86+
// 返回图片
8087
const newRes = new Response(object.body, {
8188
status: 200,
8289
headers,
@@ -129,6 +136,13 @@ export async function onRequest(context) { // Contents of context object
129136
if (fileType) {
130137
headers.set('Content-Type', fileType);
131138
}
139+
// 根据Referer设置CDN缓存策略,如果是从/或/dashboard等访问,则仅允许浏览器缓存;否则设置为public,缓存时间为1年
140+
if (Referer && Referer.includes(url.origin)) {
141+
headers.set('Cache-Control', 'private, max-age=86400');
142+
} else {
143+
headers.set('Cache-Control', 'public, max-age=31536000');
144+
}
145+
132146
const newRes = new Response(response.body, {
133147
status: response.status,
134148
statusText: response.statusText,
@@ -147,8 +161,8 @@ export async function onRequest(context) { // Contents of context object
147161
async function returnWithCheck(request, env, url, imgRecord) {
148162
const response = new Response('good', { status: 200 });
149163

150-
// Referer header equal to the dashboard page
151-
if (request.headers.get('Referer') == url.origin + "/dashboard") {
164+
// Referer header equal to the dashboard page or upload page
165+
if (request.headers.get('Referer') && request.headers.get('Referer').includes(url.origin)) {
152166
//show the image
153167
return response;
154168
}
@@ -165,14 +179,14 @@ async function returnWithCheck(request, env, url, imgRecord) {
165179
if (typeof request.headers.get('Referer') == "undefined" || request.headers.get('Referer') == null || request.headers.get('Referer') == "") {
166180
return Response.redirect(url.origin + "/blockimg", 302)
167181
} else {
168-
return new Response('Error: Image Blocked', { status: 404 });
182+
return Response.redirect(url.origin + "/static/BlockImg.png", 302);
169183
}
170184

171185
} else if (record.metadata.Label == "adult") {
172186
if (typeof request.headers.get('Referer') == "undefined" || request.headers.get('Referer') == null || request.headers.get('Referer') == "") {
173187
return Response.redirect(url.origin + "/blockimg", 302)
174188
} else {
175-
return new Response('Error: Image Blocked', { status: 404 });
189+
return Response.redirect(url.origin + "/static/BlockImg.png", 302);
176190
}
177191
}
178192
//check if the env variables WhiteList_Mode are set

static/BlockImg.png

63.9 KB
Loading

0 commit comments

Comments
 (0)