司白画博客 - 技术 2025-08-27T16:33:00+08:00 Typecho https://blog.cll.tw/feed/atom/category/%E6%8A%80%E6%9C%AF/ <![CDATA[EdgeOne边缘函数实现图片格式转换与缩放]]> https://blog.cll.tw/archives/edgeone-image.html 2025-08-27T16:33:00+08:00 2025-08-27T16:33:00+08:00 司白画 https://blog.cll.tw 前言

Edgeone 横空出世,不少博客都写上几篇相关的文章,也都用上了免费的服务。虽然 EdgeOne 还不错,但用起来还是没有 Cloudflare 方便,所以我只把静态资源放在了 EdgeOne 加速,包括我的图床(实际上是我的 R2 存储桶)

为了保证原图存储,我的图床在上传之时没有进行图片格式转换和缩放,避免以后需要用到原图时还要重新寻找图片上传。但是过大的图片也实在是考验用户的网速,影响访问体验。

EdgeOne 虽然有直接的图片处理服务,但是还要升级个人版,对于一个白嫖用户来说实在是不合适。

刚好 EdgeOne 边缘函数 有一定量的免费额度(边缘函数请求数 300万次,边缘函数 CPU Time 300万毫秒),对于我这个小小小图床那是绰绰有余的。

EdgeOne 官方文档 提供了示例函数,包含图片自适应 WebP图片自适应缩放,但是二者并不是合在一起的,或许是为了促进“图片处理服务”的使用吧。如果没有示例函数,对于函数的书写还是有点费劲的,还要把原本那么多文档喂给 ChatGPT。不过现在就很简单了。

我们可以借助ChatGPT把两个示例函数进行合并,实现图片自适应转换与缩放,并且不用改变原有图片的链接!这是最为方便的。

分函数

图片自适应 WebP

在文档的最佳实践里面还有一版根据浏览器转换不同格式的,我觉得太过麻烦,所以直接自适应转换 WebP 就好了。

async function handleEvent(event) {
  const { request } = event;
  
  // 获取客户端支持的图片类型
  const accept = request.headers.get('Accept');
  const option = { eo: { image: {} } };
  
  // 检查客户端是否支持 WebP 格式的图片,若不支持响应原图
  if (accept && accept.includes('image/webp')) {
    option.eo.image.format = 'webp';
  }
  
  const response = await fetch(request, option);
  return response;
}

addEventListener('fetch', event => {
  // 当函数代码抛出未处理的异常时,边缘函数会将此请求转发回源站 
  event.passThroughOnException();
  event.respondWith(handleEvent(event));
});

图片自适应缩放

经过体验,我感觉图片自适应缩放比单纯的图片质量压缩好,图片自适应缩放可以让质量更小,并且不太影响观感,因为图片的尺寸也更小了。

addEventListener('fetch', event => {
  // 当函数代码抛出未处理的异常时,边缘函数会将此请求转发回源站 
  event.passThroughOnException();
  event.respondWith(handleEvent(event));
});

async function handleEvent(event) {
  const { request } = event;
  const urlInfo = new URL(request.url);
  const userAgent = request.headers.get('user-agent');

  // 请求非图片资源
  if (!/\.(jpe?g|png)$/.test(urlInfo.pathname)) {
    return fetch(request);
  }

  // 移动端图片宽度
  let width = 480;
  const isPcClient = isPc(userAgent);

  // PC 端图片宽度
  if (isPcClient) {
    width = 1280;
  }

  // 图片缩放
  const response = await fetch(request, {
    eo: {
      image: {
        width,
      }
    }
  });

  // 设置响应头
  response.headers.set('x-ef-client', isPcClient ? 'pc' : 'mobile');
  return response;
}

// 请求客户端类型判断
function isPc(userAgent) {
  const regex = /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i;
 
  if(regex.test(userAgent)) {
    return false;
  }
  
  return true;
}

合函数:图片格式自适应转换与缩放

我自然是不会合并的,那就交给 ChatGPT 吧。通过图片格式自适应转换与压缩,一箭双雕,再也不用担心博客图片加载慢的问题了。

函数代码

addEventListener('fetch', event => {
  // 当函数代码抛出未处理的异常时,将请求转发回源站
  event.passThroughOnException();
  event.respondWith(handleEvent(event));
});

async function handleEvent(event) {
  const { request } = event;
  const urlInfo = new URL(request.url);
  const userAgent = request.headers.get('user-agent');

  // 请求非图片资源,直接返回
  if (!/\.(jpe?g|png)$/i.test(urlInfo.pathname)) {
    return fetch(request);
  }

  // 判断客户端类型
  const isPcClient = isPc(userAgent);

  // 移动端图片宽度
  let width = isPcClient ? 1280 : 480;

  // 获取客户端支持的图片格式
  const accept = request.headers.get('Accept');
  const imageOptions = {};

  if (accept && accept.includes('image/webp')) {
    imageOptions.format = 'webp';
  }

  // 图片请求
  const response = await fetch(request, {
    eo: {
      image: {
        width,
        ...imageOptions
      }
    }
  });

  // 设置响应头
  response.headers.set('x-ef-client', isPcClient ? 'pc' : 'mobile');
  return response;
}

// 判断是否为 PC 客户端
function isPc(userAgent) {
  const regex = /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i;
  return !regex.test(userAgent);
}

功能说明 By ChatGPT

  • PC 客户端宽度 1280,移动端 480。
  • 支持 WebP 格式的客户端返回 WebP,否则使用原格式。
  • 非图片请求直接返回原始资源。
  • x-ef-client 响应头标识客户端类型。

部署函数

新建函数规则

EdgeOne 后台 进入站点,在左侧边栏选择边缘函数,新建一个函数,随意选择一个模版,把函数代码替换成上面的合函数,然后创建并部署。

新建函数规则

新建触发规则

进入刚才创建的那个函数,点击新建触发规则,匹配类型选择HOST,运算符选择等于,值选择为你的图片存储域名,直接确定即可。

新建触发规则

至于文件后缀限定条件,我觉得可有可无,因为函数本身已经判断过文件是否为图片了。不过如果图片本身有文件后缀,可以再次加上限定条件:pngjpgjpeg请不要带上.,否则函数将会无法触发。

对于 Gravatar 的镜像站来讲,文件后缀就没有必要限定了,因为 Gravatar 的头像链接是不带文件后缀的,如果限定了文件后缀将会无法转换为 WebP 格式。

似乎这个函数代码对于 Gravatar 镜像站无效,可能是因为在函数代码中检测了一次图片类型,所以即使在前端的我触发条件没有限制文件后缀,依然无法转换。

对于这个问题,可以使用不进行文件后缀判断的函数代码,并把文件后缀判断的限定移到前端的触发条件中。我们可以对Gravatar 镜像域名单独设定一个触发条件,在前端也不判断文件后缀。

// 没有作用,请不要使用
async function handleEvent(event) {
  const { request } = event;
  const userAgent = request.headers.get('user-agent');
  const isPcClient = isPc(userAgent);
  let width = isPcClient ? 1280 : 480;

  const accept = request.headers.get('Accept');
  const imageOptions = {};
  if (accept && accept.includes('image/webp')) {
    imageOptions.format = 'webp';
  }

  try {
    const response = await fetch(request, {
      eo: {
        image: {
          width,
          ...imageOptions
        }
      }
    });
    response.headers.set('x-ef-client', isPcClient ? 'pc' : 'mobile');
    return response;
  } catch (e) {
    // 如果不是图片或处理失败,返回原始请求
    return fetch(request);
  }
}

好像怎么改都没用,可是我记得之前的只转换格式代码是可以的。不管了,反正 Gravatar 头像 本身不是很大,转不转换区别不大,开个缓存就好了。

测试效果

现在来访问部署完函数的站点图片,虽然链接的末尾还是原本的文件后缀,但是打开检查工具,在网络中找到这张图片,就会发现文件类型已经变成了image/webp

效果图

再点击一下图片,就会发现图片尺寸变小了,没有原来那么大了,但依然是很清晰的。

最后把图片下载下来,发现图片的大小小了很多,并且下载下来的文件后缀为webp

我也来这里放一个测试链接:https://cdn.cll.tw/img/2025/08/1755540774.jpg

原图

测试图片

原本大小为 7.7 MB 的图片,现在已经变为 562 KB 了,加载起来都非常丝滑。

参考资料

图片自适应 WebP:https://edgeone.ai/zh/document/57423?product=edgedeveloperplatform
图片自适应缩放:https://edgeone.ai/zh/document/54770?product=edgedeveloperplatform
通过边缘函数实现自适应图片格式转换:https://edgeone.ai/zh/document/54768?product=edgedeveloperplatform

结语

EdgeOne 也变成大善人了......

通过 EdgeOne 边缘函数,可以让图片自适应格式转换与缩放,浏览体验大大提升,也不会影响原图的存储,未来可操作性很强。

不过目前博客只有大图片放在了图床上,截图什么的还是存储在本地。虽然有 Typecho 直接上传到兰空图床的插件,但感觉还是存在本地保险。

等一会还是迁移一下,双端备份也比较保险呢,速度也能提升一下。截图什么的就不压缩了,清清晰晰的比什么都好。

好像有一个问题,自适应图片在第一次访问的时候需要进行转换,所以很慢。但之后就能快起来了呢。

还有一个问题就是移动端的缩放太狠了,只考虑了显示大小,却没有考虑放大后的大小。建议将移动端的自适应宽度改为和 PC 端一样。

]]>
<![CDATA[一键透视不太灵付费资源]]> https://blog.cll.tw/archives/free-bt0.html 2025-08-26T17:58:00+08:00 2025-08-26T17:58:00+08:00 司白画 https://blog.cll.tw 前言

不太灵曾经是我最喜欢的影视下载站,可是自从它改版之后,所有资源都要会员了,而且还非常贵,我自然是出不起。今天又访问了不太灵看看,发现所谓的付费资源只是被加上了一个遮罩,实际上资源链接已经显示在前台了,我们只需要通过浏览器检查工具去掉遮罩就可以了。

VIP的付费弹窗可以直接使用选择工具删除,但是剩下的遮罩如果选择删除,整块区域就会消失,因此需要将这部分的遮罩样式去除。在 ChatGPT 的帮助下,我得出了以下方法。

最终效果

二合一书签脚本 最终效果

步骤

第一步:删除VIP付费弹窗

删除VIP付费弹窗

1. 右键-检查或点击 F12 按键打卡浏览器的检查工具

2. 接着点击选择工具,选择 VIP 付费弹窗区域

3. 按下你的删除键,VIP 弹窗消失

虽然此刻弹窗已经消失,但是遮罩还在,所以我们还需要去除遮罩。

但是使用前面这个删除办法已经无法去除遮罩了,而是会让整块区域消失。

所以我们需要把遮罩的 CSS 样式给删除,实现透视效果。

第二步:删除遮罩 CSS 的样式

基本方法:临时去掉样式

通过 ChatGPT 的分析,我明白了这个遮罩的本质就是filter: blur(5px); pointer-events: none; user-select: none;

所以我们只需要使用选择工具选择遮罩,在元素树里找到filter: blur(5px); pointer-events: none; user-select: none;这一层,双击选中,删除即可。

或者在旁边的样式表中,把这一样式的勾选取消。
临时去掉 CSS 样式(补图)
这时我们就会发现遮罩已经消失,我们就可以直接看到遮罩下的资源了。
透视成功

进阶方法 1:控制台执行 JS 代码一次性去掉遮罩

同样的,在检查工具中选择控制台,粘贴以下代码并回车,遮罩也是消失了。

document.querySelectorAll("div[style*='blur']").forEach(el => {
  el.style.filter = "none";
  el.style.pointerEvents = "auto";
  el.style.userSelect = "auto";
});

控制台执行 JS 代码一次性去掉遮罩

但是这个方法有点鸡肋,虽然直接使用代码去除遮罩很方便,但依然要执行第一步的删除VIP弹窗,不如也直接临时删除 CSS 样式来得方便。

进阶方法 2:写 CSS 覆盖

执行方法同上。

const style = document.createElement("style");
style.innerHTML = `
  [style*="blur"] {
    filter: none !important;
    pointer-events: auto !important;
    user-select: auto !important;
  }
`;
document.head.appendChild(style);

懒人方法:使用一键书签脚本 (bookmarklet)

在浏览器书签栏里添加一个书签,名称随意,链接改为以下代码:

javascript:(function(){document.querySelectorAll("div,span,section,article").forEach(el=>{if(el.style.filter&&el.style.filter.includes("blur")){el.style.filter="none";el.style.pointerEvents="auto";el.style.userSelect="auto";}});alert("模糊遮罩已移除");})();

在遇到这个遮罩时,只需要点击一下这个书签,遮罩就会消失,很是方便。

但同样鸡肋的是,这个书签依然只是去除遮罩,却不能先去除遮罩上面的VIP弹窗,依旧需要手动删除弹窗,方便何在?

二合一JS代码

既然第二步可以直接使用控制台执行 JS 代码删除,那么第一步也可以,那就可以直接合二为一。第一步的JS删除代码直接让 ChatGPT 搞定。二合一JS代码如下:

// 删除 VIP 覆盖层
document.querySelectorAll('.vip-gate-overlay').forEach(el => el.remove());

// 再去掉遮罩样式
document.querySelectorAll("div[style*='blur']").forEach(el => {
  el.style.filter = "none";
  el.style.pointerEvents = "auto";
  el.style.userSelect = "auto";
});

至于那个浏览器书签脚本,ChatGPT 做出来的好像没有什么用,我也懒得再去调教它了。

二合一书签脚本(Bookmarklet)

还是调教一下吧,把二合一的JS代码喂给 ChatGPT,再让它输出了二合一书签脚本。使用方法同第二步的书签法,但是只要使用二合一的就可以了。如此一来,只需要点击一下书签,不太灵就会乖乖交出资源了。

javascript:(function(){document.querySelectorAll('.vip-gate-overlay').forEach(el=>el.remove());document.querySelectorAll("div[style*='blur']").forEach(el=>{el.style.filter="none";el.style.pointerEvents="auto";el.style.userSelect="auto";});alert("遮罩已移除");})();

结语

ChatGPT 帮了大忙......

不过文字稿都是我自己写滴,只有代码是 ChatGPT 编的,其中不乏我的缝缝补补。

就算没有代码可以手动删除遮罩,不失优雅。

不太灵虽然加上了VIP可见,但只是加了一个遮罩,并不需要登录了 VIP 才显示,不知道是它的善良还是漏洞。

等到不太灵改为检测到VIP才输出资源的时候,这个方法就已经失效了......

]]>
<![CDATA[Casdoor 实现 OpenList 单点登录]]> https://blog.cll.tw/archives/casdoor.html 2025-08-25T23:13:00+08:00 2025-08-25T23:13:00+08:00 司白画 https://blog.cll.tw 前言

因为各个站点之间的登录是独立的,一个一个登录很麻烦,况且有一个单点登录系统很酷,于是我之前就很想搞一个。但是奈何这东西有点复杂,于是几番折腾之下我放弃了。

最近又看到博友在搞Casdoor,于是我重拾旧本,重新探索,终于在搜索引擎与ChatGPT的帮助之下部署完成。

环境

  • 1Panel 面板
  • Docker(基于1Panel面板的应用商店)
  • OpenResty(反代服务,大坑!!!)

流程

1. 在1Panel 应用商店安装 Casdoor

Casdoor是一个支持 OAuth 2.0、OIDC、SAML 和 CAS 的 Web UI 优先的 IAM/SSO 平台。

2. 在1Panel 网站添加应用 Casdoor

即为反代本地8000端口,同时记得配置https证书并解析域名到服务器ip。

3. 在 Casdoor 上创建基本信息

初始账号为admin,密码为123,进入后台后按照下图进行配置。
Casdoor 单点登录配置(源于Openlist文档)

4. 在 OpenList 上配置单点登录

单点登录平台选择OIDC单点登录端点名称为 Casdoor 的链接,末尾不带/

其他按照上图进行填写。

5. 测试登录:错误!

就在我满心欢喜地开始使用单点登录时,不幸的事情发生了:

{"code":400,"message":"404 Not Found: \u003chtml\u003e\r\n\u003chead\u003e\u003ctitle\u003e404 Not Found\u003c/title\u003e\u003c/head\u003e\r\n\u003cbody\u003e\r\n\u003ccenter\u003e\u003ch1\u003e404 Not Found\u003c/h1\u003e\u003c/center\u003e\r\n\u003chr\u003e\u003ccenter\u003eopenresty\u003c/center\u003e\r\n\u003c/body\u003e\r\n\u003c/html\u003e\r\n","data":null}

6. 寻找错误

于是我就把这个错误贴给了ChatGPT,它给我的答复是:

反代/网关配置问题:你前面有 Nginx/OpenResty 做反代,结果转发的时候找不到后端对应的 location,返回 404。

但是ChatGPT给出的解决办法并没有什么用......于是我开始控制变量来验证错误:

  • 使用原端口原ip:可以
  • 使用反代ip:不可以
  • 使用https域名:不可以
  • 使用http域名:不可以

因此可以得出,问题的确是在OpenResty的反代上。

7. 解决反代问题

我在搜索引擎上试图寻找遇到相同问题的文章,可惜没有。但是我知道了Casdoor的请求接口是:/.well-known/openid-configuration,因此原来的404问题就出现在这个接口上。

我看到这个接口就有点发现问题所在了,中间的一个文件夹为/.well-known,有次域名验证,文件上传到这个文件夹也是404。

于是我就把问题丢给了ChatGPT,它给了我解决方案:

# 新增 location,放在 ^~ /.well-known 之前
location = /.well-known/openid-configuration {
    proxy_pass http://127.0.0.1:8000/.well-known/openid-configuration;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

把这个添加到OpenResty配置文件中,请求接口/.well-known/openid-configuration就可以正常访问了。

再次访问OpenList单点登录,登录界面终于可以显示了,但是实际登录却又报错:

{"code":400,"message":"failed to verify signature: fetching keys oidc: get keys failed: 404 Not Found \u003chtml\u003e\r\n\u003chead\u003e\u003ctitle\u003e404 Not Found\u003c/title\u003e\u003c/head\u003e\r\n\u003cbody\u003e\r\n\u003ccenter\u003e\u003ch1\u003e404 Not Found\u003c/h1\u003e\u003c/center\u003e\r\n\u003chr\u003e\u003ccenter\u003eopenresty\u003c/center\u003e\r\n\u003c/body\u003e\r\n\u003c/html\u003e\r\n","data":null}

于是我又请教了一番ChatGPT,它又给出了解决方案:

和之前解决 /openid-configuration 类似,给 /.well-known/jwks 写单独 location:
location = /.well-known/jwks {
    proxy_pass http://127.0.0.1:8000/.well-known/jwks;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

我再次添加到配置文件中,最后终于登录成功了!!!

总结:Casdoor 实现 OpenList 单点登录中,反代问题解决方案:

在OpenResty配置文件中加入:

# 新增 location,放在 ^~ /.well-known 之前
location = /.well-known/openid-configuration {
    proxy_pass http://127.0.0.1:8000/.well-known/openid-configuration;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}
  location = /.well-known/jwks {
    proxy_pass http://127.0.0.1:8000/.well-known/jwks;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

参考资料

https://doc.oplist.org/guide/advanced/sso#_3-5-casdoor-1
https://www.whuanle.cn/archives/21725
https://blog.xioxix.com/archives/479

结尾

折腾了一个晚上总算是把单点登录解决了,幸好有众多大佬的文章与ChatGPT的帮助,最终问题才能解决。

但是使用AI解决问题并不是如文中所述一张一帆风顺,而是布满荆棘,解决问题的过程不乏我们的坚持与思考能力。

AI的出现不是替代人类,而是帮助人类;人类可以自我选择利用AI且不被AI替代。

]]>
<![CDATA[不到50元,拿下10年.xyz域名]]> https://blog.cll.tw/archives/ten-year-xyz.html 2025-08-15T18:52:00+08:00 2025-08-15T18:52:00+08:00 司白画 https://blog.cll.tw 前几天矫揉造作地注册了一个.com域名,今天就已经无感了,我想明年就不会续费了,这个钱也是浪费了......

不过今天又非常想买一个便宜的域名,于是我下手了.xyz的10年域名。

概述

.xyz本身的价值不高,注册价格也还行,但是续费价格比.com还贵,根本不值得。

但但但是,.xyz的6位及以上域名1年只需要4.81元人民币,买十年只需要48.1元,是所有付费域名中最便宜的了。

买不了吃亏,买不了上当,人走域还在。

购买

1. 寻找一个未被注册的域名

WHO.CX上挑选一个未注册的6位数字.xyz,最好是符合你的心意的,比如生日或者某些奇怪寓意的数字。

如果被注册了就多换几个。

2. 注册域名吧

spaceship:https://www.spaceship.com/zh/

来到spaceship,基本的注册你肯定都会了,再绑定一下支付宝账号。

输入你找到的未被注册的域名,先购买1年(你也无法直接购买多年)。

购买成功后再续费9年即可。

3. 开始你的旅程吧

赶紧打开Cloudflare添加你的域名吧......

结语

50元不到的10年域名还是很值的,即使当主域名还是不够格,但当一个备用域名还是不错的。

]]>
<![CDATA[买了一个 .com 域名]]> https://blog.cll.tw/archives/bought-a-com-domain.html 2025-08-11T17:32:00+08:00 2025-08-11T17:32:00+08:00 司白画 https://blog.cll.tw 心中一直有一个执念,就是要购买一个com域名。虽然现在这个域名已经很好、很短、很让我满意了,但执念总是挥之不去。于是我还是想要买一个com域名。

但是com域名好的、短的都已经被注册了,很难挑选到一个让我满意的。而有的让我满意的却是添加出售,我实在是负担不起。

于是我在 Dynadot 二手市场上挑,可是 5、6 个字符的且低价的域名都是随便的字母组合,难以找到与我投缘的域名。

因此我决定新注册一个,长的、单词组成的、富有意义的com域名。选哪几个单词呢?两个单词组成的域名基本已经被注册了,所以只能选择 3 个单词的。

我想了很久,想出了 FreeSKy,自由天空。出自哪里呢?是《我们的爱》。

可是 freessky.com 已经被注册了,那只能加单词了。想来想去,还是加一个 my 比较好,于是成了:myfreesky.com。

检查一下,竟然还没有注册过。不过这个域名确实太长了。但我买的欲望还没有那么强。

我其实还想注册一个 sibaihua.com,毕竟这个关联性很强,但我又没有那么多钱去注册域名,于是我就在狗爹上域名估值了一下。

cll.tw

我最满意的域名竟然只估出了 $789,或许是 tw 这个 TLD 不太值钱。

myfreesky.com

而 myfreesky.com 竟然值 $1863。我想狗爹应该是太过片面的按照 my、free 等关键词进行估价了,又或许是 com 比较值钱呢?

sibaihua.com

sibaihua.com 我看起来很顺心,结果就值 $114,所以我放弃注册这个,等以后发达了再注册。

应该不会有人注册这个再来坑我......

最后的最后,我注册了 myfreesky.com,但是买了就闲置了。

Dynadot 最近有一个活动就是转发 com 域名 有机会获得 500美金,反正现在闲置就先转到我的 YouTube 了。

而且 Dynadot 的捆绑销售真是太善良了,原本购买一个 com 需要78元,结果同时购买 com、info、online 只要66元,真是赚大发了。

不过这也是 Dynadot 的一个心机,因为 info 和 online 的续费超级贵!千万不要投入生产使用,否则续费时就等着哭吧。

所以我反手就挂二手了。

其实买域名的最大快乐在于买之前的欣喜和激动,买之后我们看久了也就腻了。

]]>
<![CDATA[以 ECH 之力对抗 SNI 阻断]]> https://blog.cll.tw/archives/ech.html 2025-08-08T17:07:00+08:00 2025-08-08T17:07:00+08:00 司白画 https://blog.cll.tw 引言

一个现象:有的域名没有被墙,访问却显示连接已重置。

其实,是被SNI阻断了。

浏览器通过安全DNS和ECH即可破除SNI阻断,还我互联网。

概念介绍

抄袭Cloudflare的。

安全 DNS

传统上,DNS 查询以明文形式发送。任何在互联网上监听的人都能看到您正在连接哪些网站。

为了确保您的 DNS 查询保持私密,您应该使用支持安全 DNS 传输的解析器,例如 DNS over HTTPS (DoH) 或 DNS
over TLS (DoT)。

快速、免费、注重隐私的 1.1.1.1 解析器支持 DNS over
TLS(DoT),可以使用支持它的客户端进行配置。在此查看支持的浏览器列表。现在可以按照这些说明在 Firefox 中配置 DNS over
HTTPS。两者都可以确保您的 DNS 查询保持私密。

ECH

加密客户端 Hello (ECH)是 TLS 握手协议的一个扩展,可以防止握手的隐私敏感参数暴露给您和 Cloudflare

之间的任何人。这种保护还扩展到服务器名称指示(SNI),否则在建立 TLS 连接时会暴露您要连接的主机名。

配置

相信你已经懂了这两者的概念,那么如何配置呢。

踩坑:阿里云 安全 DNS

首先,肯定是要先配置安全 DNS。

如何配置?

以 Chrome 为例,打开设置 => 隐私与安全 => 使用安全 DNS => 添加自定义服务商:

https://223.5.5.5/dns-query

理论可行,可是在实际操作时,安全 DNS配置成功了,可ECH却无法开启。

网上给的 Chrome 开启 ECH 方法我死活是开不了,Edge 也一样。

于是乎我就再去查了查,发现:

正确做法:直接使用 Cloudflare 的 安全 DNS

设置方法同 阿里云安全 DNS,并且是 Chrome 内置的,设置非常方便。

而且我发现,使用 Cloudflare 的 安全 DNS 后,ECH是自动支持的。

验证

验证

https://www.cloudflare.com/zh-tw/ssl/encrypted-sni/

https://tls-ech.dev/

https://defo.ie/ech-check.php

访问上面任意一个网站即可检查你的浏览器是否支持 ECH 了。

小坑

验证是否支持 ECH 时请不要使用代理,否则会显示不支持。

使用 Cloudflare 的安全 DNS 后访问境内网站速度会变慢,甚至导致代理无法连接,请酌情使用。

结语

我终于可以直连我的网站了......

参考文章

https://www.notetoday.net/note/698.html

https://www.v2ex.com/t/1076154

https://zhuanlan.zhihu.com/p/3739662610

]]>
<![CDATA[使用 Cloudflare Pages 部署一个个人主页]]> https://blog.cll.tw/archives/cloudflare-pages.html 2025-08-07T14:12:00+08:00 2025-08-07T14:12:00+08:00 司白画 https://blog.cll.tw 导语

Cloudflare是一个“终极白嫖平台”,而作为一级域名,如果就给了博客,不免有些浪费。

那么,不妨在一级域名上部署一个免费的个人主页吧 ~

利用 Cloudflare 的全球网络和算力,让你的个人主页在全球部署!

ps:一个静态页面好像也不怎么需要算力......

成果展示

cll.tw

链接:https://cll.tw

几点说明:

1. 我把天气的api改为固定的了,所以无论你在哪,都显示“台北市”。

为什么呢,因为高德的api免费限制5000个请求,而我又是一个爱网站测速的人。

若是给我自己刷爆了就不好玩了。

2. 我也把一言api删除了(同样是固定的)

为什么呢?因为一言api限制短期请求数,我又爱刷新,于是一直提示一言获取失败,看了很烦,干脆直接固定了。

3. 音乐api是我自己搭建的,当然是用 Vercel 一键部署的。

因为原本的音乐api好像不能请求了,自己搭建一个也有掌控权。

提前准备

1. Cloudflare 的后台:https://dash.cloudflare.com/

要想使用 Cloudflare Pages 服务,你肯定是要有一个 Cloudflare 账号了。

当然,最好在你账号里绑定一个域名,这样子 Pages 就可以使用你自己的域名啦。

2. Github 仓库地址:https://github.com/imsyy/home

要想用 Cloudflare Pages 搭建一个网站,当然要有网站源码了。

而我们要使用的源码,就在这个 Github 仓库里。

当然,我对 Github 不是很了解,这里也不用多说了。

但是,你首先要有一个 Github 账号呀!

搭建

1. Fork Github 仓库

首先,打开 Github 仓库地址:https://github.com/imsyy/home

但这个源码,现在在别人的仓库里,自然不是你的,你又要如何修改呢?

所以,先在别人的 Github 仓库里,把仓库给 Fork 下来,就到你的仓库里了。

(由于我已经 Fork 过了就不再展示,但是 Fork 键 你肯定知道在哪,对吧!)

Fork 键

很好,被你发现了。

所以你一顿操作猛如虎就到你仓库里啦。

2. 在 Cloudflare Workers => Workers 和 Pages 里创建 一个 Pages

首先,这个 计算 Workers 的入口不是在域名里,而是在Cloudflare控制台的首页 => 右边的边栏里。

切换到 Pages 那栏里,点击 导入现有 Git 存储库 的 开始使用。

导入现有 Git 存储库

在这里,自然是要授权 Github 账户啦。

授权完成后,选择你 Github 的那个存储库,一般来说就是home,然后点击开始设置。

3. 设置构建和部署

这是非常重要的,因为不知道为什么 Cloudflare 这么傻,不会帮你自动填写 构建命令 和 构建输出目录。

当然,框架预设是不用选择的。

构建命令:pnpm build

构建输出目录:dist

如果你不填这些,Cloudflare 依然会构建成功。

可是当你满怀欣喜地打开你的网站,却发现什么都没有,不免落空。

4. 将信息变为你的

因为这里是 Fork 别人的仓库,信息自然不是我们的。

那要如何填入自己的信息呢?

其实官方文档已经写得很清楚啦。

不过这里还是再点一下吧。

1. 主要信息

打开你的 Github 仓库,点击根目录下的 .env.example 文件并进入,再点击右上角编辑图标。

此时,上方的名称就可以更改啦。

自然,是把.env.example重命名为.env,再把相关信息改为你的。

最后,点击右上角那个绿绿的键,一顿点击就可以啦。

这时,你打开 Cloudflare Pages 的后台,就会发现它正在自动部署啦。

如此,你每次在 Github 仓库 所做的更改,Cloudflare 都会察觉并自动帮你部署啦。

当然,每次部署都会有一个专属链接,这个链接往往是你的 Pages 域名前再加上一些数字字母。

通过这些专属链接,你可以实时查看你的更改,避免缓存的影响。

但是在实际使用时,依旧是要用自己的域名啦。

2. 其他信息

说实话我已经不想再写了,请打开你的 Github 仓库,查看官方的文档把。

但是,你要注意,把站点链接和联系方式都改掉哦。

注意事项

绑定域名

在 Cloudflare Pages 的设置里哦。

我修改了信息,Cloudflare 也自动部署了,怎么没有变化呢?

这是因为缓存,有可能是浏览器的缓存,也可能是 Cloudflare 的缓存。

若要立马查看,请使用新部署的专属链接。

当然,打开浏览器的无痕模式用你的域名也是可以的啦。

结尾

天哪写得乱七八糟的,不过应该无人看,很好。

如果有不会的当然可以问我啦,说不定我也不会。

每次写这种教程类的文章都好累,而且也很难把握的住尺度。

究竟是详细一点好还是简单一点好呢?

大佬不屑于看,小白又看不懂,嘤嘤嘤。

]]>
<![CDATA[Wget 爬取 完整的 HTML 网页]]> https://blog.cll.tw/archives/crawl-html.html 2025-05-31T21:40:00+08:00 2025-05-31T21:40:00+08:00 司白画 https://blog.cll.tw 缘起

今天没事回想起了以前的.tk域名,于是到Dot Tk网站浏览了一番。

发现这个网站特别精美,尤其是它的壁纸非常有海岛特色,而且能够随机切换。

于是我就想把这个网站给保存下来。

可是,如果用浏览器直接保存的话,页面就会有很多元素缺失,且网页也会变成静态的。

于是我就询问了一个DeepSeek,得到了使用wget工具爬取html网页的方法。

代码

wget --mirror --convert-links --adjust-extension --page-requisites --no-parent http://example.com

参数说明

--mirror: 镜像模式
--convert-links: 转换链接为本地可用
--adjust-extension: 调整文件扩展名
--page-requisites: 下载所有页面资源(CSS、JS、图片等)
--no-parent: 不爬取父目录

执行方法

使用ssh终端连接Linux服务器或使用宝塔面板的终端执行命令。

下载完成后会在执行文件夹下生成一个文件夹,即为爬取的网站。

]]>
<![CDATA[网盘,没有一个好东西]]> https://blog.cll.tw/archives/bad-netdisk.html 2025-01-25T14:25:00+08:00 2025-01-25T14:25:00+08:00 司白画 https://blog.cll.tw 起因

由于最近日益注重数据的存储,所以准备开始选一家网盘作为年费使用。

选择无疑是非常困难的,因为国内各种网盘数不胜数。

但实际上又无可选择,因为国内的大部分网盘都和谐得很厉害。

但在我心目中和谐最厉害的,还是阿里云盘。

阿里和谐王

阿里云盘横空出世时,自称不限速。

当时以百度网盘为主力的我也入坑了阿里云盘。

因为使用得多了,也发现了它的尿性————各种和谐。

无论是政治还是黄色,它一律和谐。

无论是在资源库还是保险箱中,它一律和谐。

而且到现在,它甚至开始了限速。

果然,国内的网盘就没有一个可信的。

于是我重新回到了百度网盘。

百度的怀抱是否温暖?

也是和谐王

看到了曾经那些珍贵的数据依然存在,我毅然决然地开通了百度网盘的年卡,成为了SVIP2。

但是,只有我开始认真使用时,才发现,百度网盘也是一坨。

它和谐得跟阿里云盘一样,甚至更加厉害。

一切有关政治的书籍全都被封禁了,不过阿里云盘也是这样。

但是,压缩包能够幸免一下。

然而,你只要手贱双击压缩包,它就会被在线解压,百度网盘就会开始入侵你的压缩包,

将你的压缩包一览无余,随后将整个压缩包封禁。我真的会无语。不过,我当然知道它的尿性,重要资料都另用Onedrive存储了一番。

至此,百度网盘也成功让我后悔了。

我是个很喜欢稳定的人,所以我选择了百度网盘,选择了开年费。

但我又是个容易后悔的人。

然而,这一切已无法改变。

百度网盘也只能勉强备份一下手机图片和日常资料了。

那我的年费又有何用呢?

云下载,好的

幸好,百度网盘的云下载功能还是不错的。

虽然有的冷门资源下不下来,但是近期的热门资源都还是OK的。

这不就成为我的影视库备选方案了吗。

但是,我害怕会员过期,害怕存储爆满。

毕竟,百度网盘是要作为我的主力网盘的。

所以我只用百度网盘存一些最近要看的电视,或者只有百度网盘有资源的电视。

那我想要收藏的影视资源存在哪里呢?

变心的115

当然是115网盘。虽然业界经常传言115网盘要跑路了,但直到现在,115网盘依然屹立不倒。

甚至,它对普通用户也没有丝毫限速。

但最令人震惊的,是它不会和谐。

是这样的,我存在115网盘上的任何敏感资源都没有被和谐过。

还有一个优点就是,它的内存真的非常大。

只需要在闲鱼上花十几块就能得到一个15TB左右的账号。

这样看来,115网盘简直就是国内的网盘之神。

而且,它的会员在暑假时只要115元。

那我为什么没有选择115呢,因为,我害怕它跑路。

数据的价值是最为重要的。

若115跑路了,那么它的一切优点都将失效。

还有一点,它的备份功能真的太难用了,或者说,它的APP真的太臃肿了,甚至比百度网盘还卡。

这是我无法忍受的。

所以,现在115网盘只作为我的影视收藏库。

但是,115网盘是我重要的数据底裤。

[scode type="blue"]补充一点,115网盘是刀子嘴豆腐心。虽然它在用户协议里说普通用户限速100KB,但是实际上没有限速。不像某些网盘,自称不限速,到后来又开始限速,言行不一,令人可笑。[/scode]

[scode type="yellow"]2025年3月最新更新:115网盘开始限速250KB了,我的影视存储库计划彻底作废。[/scode]

百度,还行

回到主题,百度网盘真的那么烂吗?

其实不然。

作为国内市场占有率第一的网盘,或者说最多人使用的网盘,它跑路的可能性最小,功能最为成熟,是作为养老安家的不二之选。

虽然在我未开通百度网盘会员之前,我一见到百度网盘的资源就十分头痛,因为它限速100KB,要下到猴年马月才能下完啊。

但是开通会员后,百度网盘的带宽实际上是能跑满的,是能和115网盘的免费版匹敌的。

但是,百度网盘在Alist端限速在5MB左右,还是太吝啬了。

而且和谐这种东西真的很讨厌,使得我现在重要敏感资料都需要压缩加密后上传。

不明攻击对象的升华?

网盘变得越来越麻烦,数据使用变得越来越复杂,这一切都是谁害的?

不言而喻。

]]>
<![CDATA[免费SSL看Cloudflare]]> https://blog.cll.tw/archives/free-ssl.html 2025-01-23T14:12:00+08:00 2025-01-23T14:12:00+08:00 司白画 https://blog.cll.tw 背景

Cloudflare作为一家专为白嫖而生的企业大家自然是熟悉。

可是要问起来如何正确食用Cloudflare的免费SSL服务时,或许很多人就说不清了。

我曾经在互联网上搜过许多教程,但无一是有效的。

或许可能是我没有查找到精髓。

不过,我想,如今,我已正确掌握了Cloudflare的免费SSL服务食用方法。

通过这个方法,你无需在其他网站上再申请SSL证书,也无需通过各种繁琐的域名所有权验证,你只需要把你的域名托管到Cloudflare上即可。

相关链接

https://dash.cloudflare.com/

流程

一、将域名托管到Cloudflare

这一步相信很多人已经做到了,网上亦有很多教程,这里不再赘述。

二、在源服务器上安装Cloudflare的源服务器证书

注意,这个源服务器证书不能脱离Cloudflare的服务单独使用,否则浏览器会报不安全提示。(即必须使用Cloudflare的流量代理服务)

1.登录Cloudflare后台,选择一个域名,进入你的域名的后台(管理中心)。

2025-01-23T05:59:29.png

2.在左侧栏中选择SSL/TLS——源服务器证书,并创建证书。

2025-01-23T06:02:07.png

3.在宝塔面板或虚拟主机面板安装该源服务器证书。

点击下载键查看该证书的内容秘钥。请注意保存相关信息。部分信息无法再次查看。

打开宝塔面板或虚拟主机面板,分别将内容秘钥填入框中。

2025-01-23T06:04:24.png

[scode type="blue"]不建议在SSL中打开强制https,避免与Cloudflare的功能重复造成网站无法访问。[/scode]

这个源服务器证书有效期为15年,但是它不能脱离Cloudflare单独使用。所以就有了接下来的步骤。

三、在Cloudflare中配置SSL服务

在左侧栏中选择SSL/TLS——概述,将SSL/TLS 加密模式配置为完全

2025-01-23T06:10:12.png

四、大功告成

现在,你的网站应该已经能通过https访问了。而实际网页上显示的证书为谷歌诚信所颁发。

结语

通过Cloudflare所申请的证书,不仅申请方式简单,并且还能自动更新,免去了许多麻烦工作。

]]>