Skip to content

Commit 7a93da0

Browse files
committed
Changed index page initialization to use runOnHtmlDone
1 parent e7a3de7 commit 7a93da0

File tree

12 files changed

+37
-37
lines changed

12 files changed

+37
-37
lines changed

404.html

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@
1212
<script>
1313
const cardE = document.querySelector(".content-card");
1414
cardE.style.display = "none";
15-
if (cardE.classList.contains("fade-in-animation")) {
16-
cardE.classList.remove("fade-in-animation");
17-
}
1815
</script>
1916
<section style="text-align: center;">
2017
<h1 style="font-size: 4.6rem;

_posts/original/2024-03-07-解决阿里云OSS无CDN时的流量风险.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ cover:
1010
tags: Code Blog 云计算 阿里云 OSS 对象存储 Referer 函数计算 CDN 网络攻击
1111
---
1212

13-
对个人博客而言阿里云的`OSS对象存储`服务非常适合存放诸如图片、视频、`JS``CSS`的静态资源,尤其非备案的海外站点,把资源托管在国内云上是在无法使用`CDN`的条件下加速访问的几乎唯一解,从我2年来的使用体验来看对速度和稳定性都十分满意
13+
对个人博客而言阿里云的`OSS对象存储`服务非常适合存放图片、视频、`JS``CSS`之类的静态资源,尤其非备案的海外站点,把资源托管在国内云上是在无法使用`CDN`的条件下加速访问的几乎唯一解,从我2年的使用体验来看对速度和稳定性都十分满意
1414

1515
![](https://apqx.oss-cn-hangzhou.aliyuncs.com/blog/original/20240305/aliyun_oss_overview_thumb.jpg){: loading="lazy" class="clickable clickShowOriginalImg" alt="Aliyun OSS overview" }
1616

17-
阿里`OSS`并不“廉价”,但普通博客存储的数据不会很多,流量也不会很大,以`标准存储`+[按量计费](https://www.aliyun.com/price/product?spm=a2c4g.11186623.0.0.14e17bbeBxYDQ9#/oss/detail/ossbag){: target="_blank" }计算,每GB存储0.12元,每GB流量0.25~0.5元,我的博客每月费用不过1元左右,约等于免费。
17+
`OSS`并不“廉价”,但普通博客存储的数据不会很多,流量也不会很大,以`标准存储`+[按量计费](https://www.aliyun.com/price/product?spm=a2c4g.11186623.0.0.14e17bbeBxYDQ9#/oss/detail/ossbag){: target="_blank" }计算,每GB存储0.12元,每GB流量0.25~0.5元,我的博客每月费用不过1元左右,约等于免费。
1818

1919
## 非正常
2020

@@ -31,7 +31,7 @@ tags: Code Blog 云计算 阿里云 OSS 对象存储 Referer 函数计算 CDN
3131

3232
有些案例阿里云会减免一部分受攻击的费用,但毕竟它确实向运营商付出了外网流量成本,所以剩余费用还是要用户支付。对使用`OSS`的小博主,这种巨额流量像一把悬在头上的达摩克利斯之剑,随时落下。
3333

34-
首先`Referer防盗链`对这种恶意流量攻击是没用的,伪造`Referer`非常简单,它只能起到防止被其它站点`盗链`的作用。此外最直观的解决方法就是`流量封顶``带宽限制``IP请求数限制`,但奇怪的是不止阿里云,其它云服务商的`对象存储`也都不提供这类细粒度控制功能。而它们的`CDN内容分发网络`却提供,并且流量费用更便宜,大概只有`OSS`的一半,所以外套一层`CDN`再配合它更细致的流量、带宽控制手段就是应对这种攻击行为最合适的方法。
34+
首先`Referer防盗链`对恶意流量攻击是没用的,伪造`Referer`非常简单,它只能起到防止被其它站点`盗链`的作用。此外最直观的解决方法就是`流量封顶``带宽限制``IP请求数限制`,但奇怪的是不止阿里云,其它云服务商的`对象存储`也都不提供这类细粒度控制功能。而它们的`CDN内容分发网络`却提供,并且流量费用更便宜,大概只有`OSS`的一半,所以外套一层`CDN`再配合它细致的流量、带宽控制手段就是应对这种攻击行为最合适的方法。
3535

3636
只不过大陆法规不允许非备案站点使用国内`CDN`,如果用国外`Cloudflare`这样无需备案、无限流量的免费`CDN`在国内访问又会是南辕北辙。本来低延时的`OSS`请求经`CDN`到国外绕一圈后,虽然面对流量攻击无需回源不会产生流量费用,但速度必然下降,与使用`OSS`的加速初衷背道而驰,称其“减速`CDN`”也不为过。
3737

@@ -41,9 +41,9 @@ tags: Code Blog 云计算 阿里云 OSS 对象存储 Referer 函数计算 CDN
4141

4242
## 函数计算
4343

44-
按照以上思路,需要搭建一个`HTTP服务`来执行`OSS`的权限变更操作,基于`Serverless``Function Compute函数计算`是一个很好的选择`Serverless`即无需购置`服务器`,只要提供一个匹配`HTTP`请求的`函数`,它会在云服务商收到请求时被触发执行,其余时间则不消耗计算资源,也不产生费用,是`按量付费`思路下的最优解
44+
按照以上思路,需要搭建一个`HTTP服务`来执行`OSS`的权限变更操作,基于`Serverless``Function Compute函数计算`是一个好选择`Serverless`即无需购置`服务器`,只要提供一个匹配`HTTP请求`的程序,它会在云服务商收到`请求`时被触发执行,其余时间不消耗计算资源,也不产生费用,是`按量付费`思路的最优解
4545

46-
[阿里云的函数计算](https://www.aliyun.com/product/fc){: target="_blank" }费用非常低,低到什么程度呢,调用价格`0.009元/万次`,算力价格`0.00009元/vCPUx秒`,内存价格`0.000009元/GBx秒`对这种很少触发的监控需求来说是等于0的
46+
[阿里云的函数计算](https://www.aliyun.com/product/fc){: target="_blank" }费用非常低,低到什么程度呢,调用价格`0.009元/万次`,算力价格`0.00009元/vCPUx秒`,内存价格`0.000009元/GBx秒`对这种很少触发的监控需求是等于0的
4747

4848
一个调用`OSS`权限变更`API`的示例:
4949

@@ -84,10 +84,12 @@ private fun shutdownOSS() {
8484
}
8585
```
8686

87-
注意`HTTP`触发的`函数计算``Spring``Ktor`处理`HTTP`请求的行为并不一样,阿里云收到请求会触发对应`函数`执行,在`函数`中返回`HTTP`响应后其就会被立即终止,抛入其它线程的异步任务也不会存活,所以必须在执行完所需操作后才能返回响应。而且`函数`默认是[同步调用](https://help.aliyun.com/document_detail/2513634.html#p-5n8-0bh-2w1){: target="_blank" },报警请求在触发其执行后会等待响应,如果超过一定时间不回复,服务端收到超时反馈也会导致`函数`在未完成的情况下被终止
87+
不同云服务商的`函数计算`接口不同,很多都需要引入`SDK`按照规定的方式接收`Event`事件。阿里云的解决方案则更通用化,只是转发`请求`,能使用流行的`Spring``Ktor`等框架。其`HTTP`触发器收到`请求`后会在指定配置的实例中启动用户上传的程序,直接把`请求`转发到实例的`80`端口,收到`响应`即判断任务完成,然后终止程序
8888

89-
`函数计算`中与`同步调用`相对的还有[异步调用](https://help.aliyun.com/document_detail/2513634.html#p-ohe-t8x-ik6){: target="_blank" },阿里云会对`Header`里标识`异步调用`的请求直接返回`202`,然后再触发对应`函数`的后台执行,可用来处理一些耗时任务。对操作`OSS`而言,2核心4GB的实例`冷启动`执行完成需要2秒,为避免报警等待超时,应该定义一个轻量的同步`Trigger`,让其在触发操作`OSS``异步`任务后立即返回,这样既能启动耗时操作,也不会让报警请求等待过长时间
89+
注意`函数计算`启动的`Ktor`,其生命周期和在普通服务器上并不一样,返回`HTTP响应`后会被立即终止,抛入后台线程的任务不会存活,所以必须在执行完所有操作后才能返回`响应`。而且`函数`默认是[同步调用](https://help.aliyun.com/document_detail/2513634.html#p-5n8-0bh-2w1){: target="_blank" },如果超过一定时间不回复`报警请求``函数计算`收到超时反馈也会导致程序在未完成的情况下被终止
9090

91-
创建`Trigger`是因为报警配置只能指定`URL`,不能自定义`Header`,导致不能触发阿里云`函数计算``异步调用`,所以需要中间人
91+
`函数计算`中与`同步调用`相对的还有[异步调用](https://help.aliyun.com/document_detail/2513634.html#p-ohe-t8x-ik6){: target="_blank" },阿里云会对`Header`里标识`异步调用``请求`先返回`202`,再触发对应程序的后台执行,更适合处理耗时任务。操作`OSS``JVM`程序从`冷启动`到执行完成需耗时数秒(本例是2秒),为避免`报警`等待超时,应该定义一个轻量的同步`Trigger`,让其在触发`异步`任务后立即返回,这样既能启动耗时操作也不会让`报警请求`等待过长时间
9292

93-
做完这些之后,测试一下,如果成功的话那把悬在头上的达摩克利斯之剑也就可以扔掉了。
93+
创建`Trigger`是因为报警配置只能指定`URL`,不能自定义`Header`,导致不能触发`异步调用`,所以需要中间人。
94+
95+
做完测试一下,如果成功那把悬在头上的达摩克利斯之剑就可以扔掉了。

npm/dist/blog-404-v2.0.0.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

npm/dist/blog-index-v2.0.0.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

npm/dist/blog-post-v2.0.0.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

npm/dist/blog-scaffold-v2.0.0.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

npm/src/component/contentCard.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ body {
3333
@include cardElevationDark();
3434
}
3535

36+
// 文章卡片的默认位置向下偏移,且变为透明
3637
.fade-in-animation {
3738
transform: translateY(var(--card-animation-translate-y));
3839
opacity: 0;
@@ -43,6 +44,7 @@ body {
4344
// will-change: transform, opacity;
4445
}
4546

47+
// 启动动画,文章卡片向上移动到原位置
4648
.fade-in-animation.fade-in-animation--start {
4749
transform: translateY(0);
4850
opacity: 1;

npm/src/component/contentCard.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
// import "./contentCard.scss"
22

3-
export function initContentCard(startAnimation: boolean) {
4-
if (startAnimation) {
5-
startContentCardAnimation()
6-
}
7-
}
8-
9-
export function startContentCardAnimation() {
3+
/**
4+
* 卡片默认是偏移和透明的,初始化卡片使其恢复到原位置和不透明
5+
* @param withAnimation 是否使用动画
6+
*/
7+
export function initContentCard(withAnimation: boolean) {
108
const cardE = document.querySelector(".content-card.fade-in-animation")
11-
cardE?.classList.add("fade-in-animation--start")
9+
if (withAnimation) {
10+
// 启动动画,卡片恢复到原位置和不透明度
11+
cardE?.classList.add("fade-in-animation--start")
12+
} else {
13+
// 不启动动画,删除使卡片偏移、透明的动画class
14+
cardE?.classList.remove("fade-in-animation")
15+
}
1216
}

npm/src/component/dialog/BasicDialog.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -208,19 +208,14 @@ export const SEARCH_DIALOG_WRAPPER_ID = "search-dialog-wrapper"
208208
export const ABOUT_DIALOG_WRAPPER_ID = "about-dialog-wrapper"
209209
export const PREFERENCE_DIALOG_WRAPPER_ID = "preference-dialog-wrapper"
210210

211-
interface RootDialog {
212-
root: Root
213-
dialog: MDCDialog | null
214-
}
215-
216211
// 缓存每种dialog的root和dialog实例,即使该类型dialog的内容变化,其仍是同一个dialog对象
217212
// 每个tag都使用自己单独的Dialog
218213
let dialogContainerE: HTMLElement | null = null
219214
let rootDialogMap = new Map<string, Root>()
220215

221216
export function showDialog(_contentElement: JSX.Element, _dialogWrapperId: string) {
222217
// 如果此时html还未加载完成,确实可能出现为null的情况
223-
if (document.readyState != "complete") return
218+
if (document.readyState === "loading") return
224219
dialogContainerE = document.querySelector("#dialog_container")
225220
let root: Root | undefined
226221
if (rootDialogMap.has(_dialogWrapperId)) {

npm/src/page/404.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { showShortLinkJumpDialog } from "../component/dialog/ShortLinkJumpDialog";
33
import { consoleDebug } from "../util/log";
44
import { runOnHtmlDone, runOnPageDone } from "../util/tools";
5-
import { initContentCard, startContentCardAnimation } from "../component/contentCard";
5+
import { initContentCard } from "../component/contentCard";
66

77
runOnHtmlDone(() => {
88
initContentCard(false)
@@ -22,7 +22,7 @@ function checkJump() {
2222
consoleDebug("Url path = " + urlPath)
2323
// https://mudan.me/op01
2424
// https://mudan.me/opera
25-
var matches = urlPath.match(RegExp("^/((op|og|rp|pt|ot)..|index-opera|opera|repost|poetry|share|print|kfc)$"))
25+
var matches = urlPath.match(RegExp("^/((op|og|rp|pt|ot)\\d\\d|index-opera|opera|repost|poetry|share|print|kfc)$"))
2626
consoleDebug("Url matches = " + matches)
2727
if (matches != null && matches.length > 0) {
2828
// 检查是否符合格式,取出pid
@@ -31,9 +31,9 @@ function checkJump() {
3131
}
3232
if (pid == null) {
3333
// 不是短链跳转,如果处于404页,显示404提示(默认是不显示的)
34-
const e404 = document.querySelector(".content-card") as HTMLElement;
35-
if (e404 != null) {
36-
e404.style.display = "block"
34+
const eCard = document.querySelector(".content-card")
35+
if (eCard != null) {
36+
(eCard as HTMLElement).style.display = "block"
3737
}
3838
return
3939
}

npm/src/page/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { Post } from "../component/react/post/BasePostPaginateShow"
1111
import { GridIndexList } from "../component/react/GridIndexList"
1212
import { MDCRipple } from "@material/ripple"
1313

14-
runOnPageDone(() => {
14+
runOnHtmlDone(() => {
1515
initIndexTopCover()
1616
initIndexList()
1717
})

section/opera.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
{%- break %}
3939
{% endif -%}
4040
{%- if post.categories contains "opera" and post.hideFromIndex != true %}
41-
<li class="grid-item grid-index-li">
41+
<li class="grid-item grid-index-li" style="display: none;">
4242
<a class="index-a mdc-card grid-index-card grid-index-card__ripple" href="{{ post.url }}">
4343
<section>
4444
{%- if post.index-cover != null %}

0 commit comments

Comments
 (0)