普通视图

发现新文章,点击刷新页面。
昨天以前首页

在咖啡凉透前救回了博客数据

作者 keyle xiao
2026年3月9日 19:29

因为扩容过10GB硬盘,差点被阿里云99元续费资格拒之门外。

收到阿里云服务器到期的短信提醒时,我还在想着这台三年前入手的99元ECS主机不知不觉已经陪我走过三个年头了。登录控制台,找到那台即将到期的实例,熟练地点下续费按钮,结果弹窗没出现,按钮是灰色的,无法点击。我还以为是浏览器卡了,刷新、退出重登,依旧如此。点开人工客服窗口一问才知道,这台主机当初扩容过10GB硬盘,导致无法享受99元的特殊续费优惠。原来这种特价机的特殊待遇是有严格前置条件的,只要变更过配置,就失去了特殊续费的资格。想要继续享受优惠,唯一的办法就是将当前实例释放,用新的名额重新购买。

释放实例这四个字听起来轻松,但对一个搭建了博客、绑定了域名的服务器来说,数据怎么办、配置怎么办、IP地址变了怎么办都是问题。客服告诉我可以通过弹性网卡功能保留IP,在释放实例时将主网卡设置为不随实例释放,这样私网IPv4地址就能被保留。结果我在操作界面找了半天,才发现主网卡的保留功能目前仅在北京、上海、杭州等部分地域开放,我实例所在区并不支持。折腾了半个多小时,我放弃了IP无损迁移的计划,老老实实接受换新IP的命运。

既然IP保不住,那就得保证数据100%迁移成功。这里阿里云的镜像功能确实好用,在释放实例前,我先为老主机创建了一个自定义镜像,将系统盘的环境和数据打了个包。镜像创建完成后发现老主机在华东1上海,而新购的优惠机活动区通常在北京或张家口,镜像跨区域了怎么办?研究功能面板发现了复制镜像功能,可以将上海区域的镜像一键复制到北京区域,整个过程大概十分钟,在北京的镜像列表里就躺着我从上海搬运过来的那份数据备份。

镜像在手操作就顺畅多了,先释放老主机,释放后果然在活动页面看到了重新出现的99元购买入口,果断在北京区域下单。因为之前扩容过,镜像还原的时候也要一样尺寸的硬盘,所以再次点击续费将新机也延长一年使用时间,顺手又把数据盘扩容到了原来的大小。新机创建好后,在实例详情页选择更换操作系统、使用自定义镜像,选中从上海复制过来的那份镜像,等待几分钟系统盘被镜像数据完全覆盖,熟悉的宝塔面板、网站文件、数据库内容一个不少地回来了。

系统虽然回来了但网络不通,新机器的安全组是全新的,默认只开放了22端口和3389端口。手动添加入方向规则开放宝塔默认的8888端口,以及网站用的80和443端口,直接把原来实例的安全组规则截图对比着配了一遍。CDN和域名解析也要大调整,我一直用的是又拍云,登录又拍云控制台找到对应的服务,将回源IP从老IP修改为新IP。为了省事在域名DNS解析控制台添加了一条泛域名的A记录指向新主机IP,实现所有子域名的快速生效。备案信息更新是最容易被忽略的,登录工信部备案管理系统找到对应的网站备案信息,点击变更接入将主机IP地址更新为新的IP,如果不更新一旦被机房扫描到IP与备案不一致有被注销备案的风险。

中间其实我还动过换平台的念头,顺手申请了一台腾讯云的主机,也是99元的活动价。本来想着如果能直接迁移过去也不错,结果发现搭建web服务需要备案,要把阿里云的备案迁移过去实在是太麻烦了,折腾了一圈想想还是算了,就放弃了。不过既然机器已经申请了,闲置着也可惜,就在这台腾讯云主机上搭了个OpenClow服务,体验了一下最近比较热门的东西,也算是没白折腾这一趟。

看着博客首页重新加载出来,长舒一口气。这次续费风波算是告一段落。
记录于此,希望对遇到同样问题的朋友有所帮助。

在Lua中循环Require是如何处理的?

作者 keyle xiao
2025年8月7日 11:38

在 Lua 中,当多个脚本文件循环 require 时(例如 A 依赖 B,B 又依赖 A),最后 require 的值为 true 是由于 Lua 的 模块加载机制避免无限循环 的设计导致的:

  1. 模块加载状态跟踪:Lua 使用 package.loaded 表跟踪已加载的模块。
  2. 占位符机制:当开始加载模块 A 时,会先在 package.loaded 中设置 A = true(临时占位符)。
  3. 循环检测:若在加载 A 的过程中遇到 require B,而 B 又尝试 require A
    • 此时 package.loaded[A] 已存在(值为 true)。
    • Lua 会直接返回这个占位符值 true,避免无限循环。
  4. 最终值替换:当 A 完全加载后,其返回值会替换占位符(但循环依赖的模块已获取了占位值 true)。

在lua5.1中,出现循环require会直接报错(这边我们不讨论在5.1下的情况),如果报错是非常容易排查的,如下图:

lua5dot1error

代码案例演示

假设有两个文件互相依赖:
test_script

执行结果:
1
2
3
4
5
Start loading A
Start loading B
In B, a = true <-- 循环 require 导致值为 true
In A, b = Module B <-- B 正常加载完成
In main, a = Module A

关键点说明

  1. 加载流程
    • main.lua 执行 require "a",开始加载 A。
    • A 执行 require "b",开始加载 B。
    • B 执行 require "a",此时 A 正在加载中(package.loaded[a] = true),直接返回 true
  2. 值的变化
    • B 中的 a 获取到占位符 true
    • A 加载完成后,package.loaded["a"] 被替换为 "Module A"
    • 但 B 中已获取的 a 值不会更新(仍是 true)。

Lua 源码分析(以 Lua 5.4 为例)

关键函数在 loadlib.c 中的 ll_require 函数:

核心逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
static int ll_require (lua_State *L) {
const char *name = luaL_checkstring(L, 1);

// 1. 检查模块是否已加载
lua_settop(L, 1);
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
if (lua_getfield(L, 2, name) != LUA_TNIL) { // 已存在
if (lua_toboolean(L, -1) == 0) // 值为 false 表示加载失败
luaL_error(L, "module '%s' not found", name);
return 1;
}

// 2. 设置临时占位符 true
lua_pushboolean(L, 1);
lua_setfield(L, 2, name); // package.loaded[name] = true

// 3. 加载模块代码...
// ...(此处调用加载器执行文件内容)

// 4. 如果模块未返回值,则保持 true 不变
if (lua_getfield(L, 2, name) == LUA_TNIL) {
lua_pushboolean(L, 1);
lua_pushvalue(L, -1);
lua_setfield(L, 2, name); // 无返回值时设为 true
}
return 1;
}

关键步骤:

  1. **检查 package.loaded**:若模块已存在,直接返回其值。
  2. 设置占位符:在加载前设置 package.loaded[name] = true,标记模块正在加载。
  3. 处理循环依赖:当依赖模块尝试 require 当前模块时,直接返回占位符 true
  4. 替换最终值:模块加载完成后,用返回值替换占位符(若未返回值,则保持 true)。

解决方案:避免循环依赖

  1. 重构代码:解耦模块间的双向依赖。
  2. 延迟加载:在需要时再 require(例如在函数内部调用)。
    1
    2
    3
    4
    5
    6
    -- b.lua 修复版
    local a
    function get_a()
    if not a then a = require "a" end
    return a
    end
  3. 显式传递依赖:通过参数传递避免 require

最佳实践:模块设计应遵循 单向依赖 原则,避免循环 require。若无法避免,需明确处理占位值 true 的情况。

兰空图床(Lsky Pro)API 获取 Token 教程

作者 西风
2025年4月29日 02:43

前言

在使用兰空图床(Lsky Pro)对接第三方应用或自动化上传时,通常需要通过 API 获取用户 Token,以便后续进行认证、上传、管理图片等操作。

本教程将详细讲解如何通过 API 正确获取 Lsky Pro Token,支持 Postman、curl 命令行两种方式操作。
(适用于 Lsky Pro 2.x 版本及以上)

📌 小提示:本文以 Lsky Pro v2.1 为例,其他新版接口基本一致。


1. 准备工作

在开始之前,请确认以下几点:

  • 已部署好 Lsky Pro 图床,并可以正常访问。
  • 确认图床版本为 2.x 以上(支持标准 API 接口)。
  • 服务器 Nginx 配置正确,确保 /api/v1/ 路由能被转发到程序(否则访问 API 会 404), 正常安装的基本不用改任何配置,直接下一步就可以。
  • 已有一个注册好的 Lsky Pro 账号(邮箱 + 密码)。

2. 获取 API 地址

680fc8a8959b7.webp

Lsky Pro 标准 API 入口图床管理的后台 接口 都可以看到,https://yourdomain.com/api/v1/, 例如,如果你的图床部署在:img.yourdomain.com
那么获取 Token 的接口地址就是:https://img.yourdomain.com/api/v1/tokens, 很多AI教程说的获取地址都是token不带s,是不对,获取不到404问题。


3. 通过 Postman 获取 Token

Postman 是常用的 API 调试工具,推荐用它来第一次验证接口是否通畅。

Postman 设置步骤

680fc87d354e9.webp
680fc884d022c.webp
680fc88d106f6.webp

(1)新建请求

  • 方法:默认是GET,切换到POST
  • 地址:https://yourdomain.com/api/v1/tokens

(2)设置 Headers

Key Value
accept application/json

(3)设置 Body 两种模式

680fc893912c4.webp
点击 x-www-form-urlencoded

Key Value
email Lsky注册邮箱
password 你的Lsky密码
  • 点击 SEND 然后看下面会输出
{
    "status": true,
    "message": "success",
    "data": {
        "token": "2|VaVEjmjlCl9nHb****ULJf96reeEVY"
    }
}

然后用到你需要用的地方就可以了。

采用JSON模式获取
680fcbca7cfd3.webp

  • 点击 Body → 选择 raw → 下拉选择 JSON,填入以下内容:
{
  "email": "admin@example.com",
  "password": "yourpassword"
}

(4)发送请求

  • 点击 SEND 按钮。
  • 如果一切正确,会返回如下 JSON 数据:
{
  "status": true,
  "message": "success",
  "data": {
    "token": "1|1bJbwlqBfn**************IwqiZjCDs7r1Ob5"
  }
}

填写到你需要的地方就可以了。

❌
❌