MoreRSS

site iconSunZhongWei | 孙仲维 修改

博客名「大象笔记」,全干程序员一名,曾在金山,DNSPod,腾讯云,常驻烟台。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

SunZhongWei | 孙仲维 的 RSS 预览

修改 docker 中安装的 MySQL 的配置参数

2026-03-13 15:35:59

今天中午发现服务器磁盘又快满了。按目录顺序排查了一遍,发现是 MySQL 的 binlog 文件占用了大量空间。之前通过 mysql console 设置的 binlog_expire_logs_seconds 参数(限制保持3天)在重启 mysql docker 容器后就失效了。参考前文 设置 MySQL binlog 保存天数,节省服务器硬盘空间

好在今天的开发任务基本完成,也上线测试通过。所以就有时间来折腾一下 docker 中的 MySQL 配置了。以前是能不动就不动,主要是不太想过多了解 docker 的细节,感觉太浪费生命。但是,在自动化运维上,没搞定一项配置,就能节省以后的重复劳动,还是很有必要的。毕竟 AI 虽然可以写代码,但是我并不敢让 OpenClaw 这类神兽去线上服务器操作,还是得自己来。

使用配置文件(最推荐,易于维护)

首先我问了一下 Gemini,这是她最推荐的方式。即,创建一个自定义的配置文件,并将其挂载到容器中。在宿主机创建一个文件,例如 mysql.cnf:

[mysqld]
binlog_expire_logs_seconds=259200

259200 秒代表 3 天。在 docker-compose.yml 中挂载该文件:

services:
  mysql:
    image: mysql:8.0
    volumes:
      - ./mysql.cnf:/etc/mysql/conf.d/mysql.cnf

注:MySQL 会自动读取 /etc/mysql/conf.d/ 目录下所有以 .cnf 结尾的文件。

docker volumes 可以设置单个文件么

可以的。即支持挂载单个文件,也支持挂载整个目录。

确认 docker 中的 /etc/mysql/conf.d/ 目录是否存在

docker compose exec mysql bash

# ls /etc/mysql/
conf.d
# ls /etc/mysql/conf.d/

容器内 /etc/mysql/conf.d/ 目录存在,但是没有任何配置文件。

查看 /etc/my.cnf 文件内容,确认是否包含以下行:

!includedir /etc/mysql/conf.d/

通常在最后一行。

使新配置生效

docker compose up -d mysql

自动停止、删除旧容器,并根据新配置启动新容器。

如果只修改了宿主机上被挂载的文件内容,MySQL 通常需要重启才能读取新配置,但此时你执行 docker restart 就生效了,因为挂载关系没变,只是内容变了。

执行速度很快,感觉嗖的一下就重启好了。

心惊胆颤地检查了一下网站是否正常,以及配置是否生效,结果一切正常,binlog_expire_logs_seconds 的值也正确了。没用的 docker 知识又增加了😓

搭建 OpenClaw 并关联 Github Copilot,实现无限免费大模型 token

2026-03-11 10:33:33

本来不想凑 OpenClaw 这个热闹的,因为我似乎也没有具体的使用场景。但是,突然接到了公司领导的任务,必须在公司内部部署一套 OpenClaw。以便雇佣几个免费的数字员工来好好压榨他们。于是,不得不尝试一下了。我上午安装部署了一套腾讯版本的 OpenClaw,叫 WorkBuddy,感觉还不错,就是不能完成我的某些需求,例如:

WorkBuddy 企业微信聊天

于是我就想自己部署一套纯血版的 OpenClaw,看看是否能满足我的需求。再加上我发现 OpenClaw 还可以关联 Github Copilot,使用免费的无限 token 的模型,这个就更有吸引了。

安装 OpenClaw

参考 OpenClaw 的官网:

https://openclaw.ai

直接一行命令就能安装。例如,我在 Windows 下,打开 PowerShell,输入:

iwr -useb https://openclaw.ai/install.ps1 | iex

iwr 还是第一次见这个命令。

iwr 命令, 全称为 Invoke-WebRequest,是PowerShell中一个内置命令,它类似于 linux 中的 curl 或 wget 命令

关联 Github Copilot

安装完成后,会有一个配置引导:

在 Model/auth provider 选择 Copilot

OpenClaw Copilot

然后 Copilot auth method 选择 GitHub Copilot (GitHub device login)

OpenClaw Copilot auth method

这个 device login 跟之前安装 Github copilot CLI 的 device login 是一样的,都是本地生成一个授权码,然后去 github 网站输入授权码就能完成授权。还是非常方便的。但是注意不要在 WSL1 中这样操作(有 bug),在 PowerShell 中是正常的。参考之前整理的文档:无限免费大模型 token, Github Copilot CLI SDK 安装及测试 而且,我猜测,还是需要安装 Github Copilot CLI 的,因为之前 Copilot CLI SDK 也是必须安装 Github Copilot CLI 的。原原因是,OpenClaw 代码大概率是通过 SDK 调用 Copilot CLI 的 server mode 来使用 Copilot 的能力。SDK 负责和 CLI 进行通信,CLI 负责和 Copilot 的后端服务进行通信。流程如下:

OpenClaw
       ↓
  SDK Client
       ↓ JSON-RPC
  Copilot CLI (server mode)

虽然只是个猜测,但是大概率是这样的。

模型的选择 gpt-4o 还是 gpt-5-mini

因为 github copilot 中,这两个模型是免费无限量的。我可不想在 openclaw 中使用付费的模型,鬼知道会不会直接导致一个月 300 次的额度浪费完。
我其实不太了解这两个模型的具体区别。问了一下 gemini,他推荐的是 gpt-5-mini。给出的理由是:

OpenClaw 类工具的核心痛点是处理动态网页和反爬措施。GPT-5 mini 在视觉推理(Vision Reasoning)上有专项优化。

  • GPT-4o: 有时会分不清重叠的 DOM 元素或复杂的 CSS 布局。
  • GPT-5 mini: 对于 Canvas 渲染、复杂的 iframe 嵌套以及验证码上下文的识别准确率更高。

虽然分辨不了真假,但是我平时使用 gpt 5 mini 确实体验还不错。没有太大的问题。

聊天软件的选择

我刚开始配置的是飞书,但是我发现怎么也配置不成功,现象是飞书里的机器人不显示聊天输入框。。。可能是哪里配置出了问题吧。算了,我也不想纠结了。于是换企业微信。

用企业微信的原因是,我上午用腾讯版的 OpenClaw,即 WorkBuddy 关联过企业微信机器人,操作要简单很多,而且没有坑。飞书的配置还是太复杂,涉及的权限也多,可能是功能更强大更灵活吧。但是我只需要简单的聊天功能,企业微信就够了。具体配置参考企业微信官方的 OpenClaw 配置文档即可,写的还是非常详细的:

https://open.work.weixin.qq.com/help2/pc/cat?doc_id=21657

测试效果

哈哈,配置完成后,就能痛快体验 OpenClaw 的能力了。

OpenClaw 企业微信对话

我感觉,其实还是挺折腾的,如果没有特殊需求,直接使用腾讯版本的 WorkBuddy 就好了。
而且那个内置的免费模型还有联网搜索功能,比自己配置 OpenClaw 折腾半天,还有考虑成本的问题要省心多了。虽然 WorkBuddy 早晚还是要收费的。

golang 生成 word 文档,模板替换问题排查

2026-03-09 12:00:06

正在开发人事管理系统的入职登记表 word 导出功能,使用 golang 的 “github.com/nguyenthenguyen/docx” 包进行 word 模板替换时(参考前文: golang 对 word docx 文档中的占位符进行替换),遇到了一个诡异的问题。
就是大部分占位符都能正确替换,但有几个占位符却无法替换成功。

我开始以为是代码的问题,检查了半天没有发现问题。
然后,我又怀疑是这个三分库的 bug,可能出了异常,但是没有把 error 返回出来。
但是,感觉也不太可能,毕竟在类似的使用场景下,大部分占位符都能正确替换,说明这个库的基本功能是正常的。
最后,我才想到,可能是 word 模板本身的问题。

问了一下 DeepSeek,也印证了这种猜测。

文本被拆分

在 DOCX 的 XML 中,一个段落(

)可能由多个 (run)组成,每个 run 代表一段连续且格式一致的文本。例如,如果目标文本 “你好” 中的“你”是粗体,“好”是普通字体,它们会被分到两个不同的 run 中。Replace 方法通常只能在一个 run 内部进行简单字符串匹配,无法跨 run 查找。因此,即使文档中看起来有连续的文本,实际 XML 可能是:

<w:p>
  <w:r><w:t>你</w:t></w:r>
  <w:r><w:t>好</w:t></w:r>
</w:p>

此时,golang 代码就没法正确替换

doc.Replace("你好", "Hello", -1)

排查方法

怎么能看到 word 文件的 XML 结构呢?其实很简单,DOCX 文件本质上是一个 ZIP 压缩包,我们可以直接解压它来查看内部的 XML 文件。

  1. 将 .docx 文件的后缀改为 .zip。
  2. 直接右键解压缩这个 ZIP 文件。

可以看看这个文件夹的目录结构:

> tree
.
├── [Content_Types].xml
├── _rels
├── customXml
│   ├── _rels
│   │   └── item1.xml.rels
│   ├── item1.xml
│   └── itemProps1.xml
├── docProps
│   ├── app.xml
│   ├── core.xml
│   └── custom.xml
└── word
    ├── _rels
    │   ├── document.xml.rels
    │   └── header1.xml.rels
    ├── document.xml
    ├── endnotes.xml
    ├── fontTable.xml
    ├── footnotes.xml
    ├── header1.xml
    ├── media
    │   └── image1.png
    ├── settings.xml
    ├── styles.xml
    └── theme
        └── theme1.xml

8 directories, 18 files

这个 work 文件的结构真是非常值得学习,看起来就像是一个小型网站模板系统一样,图片和样式都被分离出来了,文档内容在 document.xml 中,样式在 styles.xml 中,图片在 media 文件夹中。
最后再用 zip 打包,只是后缀改成了 docx,真是天才。
Excel 也是类似的,特别是在大数据量下,用了 ZIP 压缩可以大大减少文件大小,相比 csv 文件来说,docx 和 xlsx 的文件大小可以小很多。

如果 Markdown 搞个扩展模式,例如 mdx, 也可以通过类似的方式把图片整合进去,感觉也很棒。

言归正传,我们打开 document.xml 文件,搜索一下正常的占位符文本(例如, 占位符 GT1 可以被正确的替换),会看到确实是没有分割:

<w:r>
	<w:rPr>
		<w:rFonts w:hint="eastAsia" w:ascii="宋体" w:hAnsi="宋体" w:cs="宋体"/>
		<w:bCs/>
		<w:sz w:val="21"/>
		<w:szCs w:val="21"/>
	</w:rPr>
	<w:t>GT1</w:t>
</w:r>

而异常的占位符(例如, 占位符 GT2)被分割成了两部分:

word xml 分割

<w:r>
	<w:rPr>
	<w:rFonts w:hint="eastAsia"/>
	</w:rPr>
	<w:t>GT</w:t>
</w:r>

<w:r>
	<w:rPr>
	<w:rFonts w:hint="eastAsia"/>
	<w:lang w:val="en-US" w:eastAsia="zh-CN"/>
	</w:rPr>
	<w:t>2</w:t>
</w:r>

这就是为什么 GT1 能被正确替换,而 GT2 却无法替换的原因了。

解决方法

最简单直接的方法,就是删掉有问题的占位符,然后手动敲一遍。

⚠:千万不要尝试从别处复制黏贴字符串过来,然后修改某个字符。word 的复制黏贴会产生意想不到的格式变化,即便你复制黏贴过来清除格式,再应用格式也不行。一定要手动敲一遍。

我现在才理解为何发票之类的文件,默认都是采用 PDF 或者图片了。Word 的格式调整能浪费你一天时间。

Latex 会不会是更好的选择呢?

Word 虽然编辑起来方便,但是遇到类似的占位符替换问题,排查起来真的非常麻烦。

不知道 Latex 会不会是更好的选择呢?毕竟它是基于文本的,直接替换字符串就行了,不会有被拆分成多个 run 的问题。

自动填充 PDF 交互式表单字段(AcroForms)

2026-03-05 14:54:11

今天在调研自动生成人事系统的入职文件时,我才知道 PDF 交互式表单字段(AcroForms)这个东东。我以为 PDF 格式就是不能编辑的。。。原来 PDF 是可以包含类似网页 form 表单的,可以直接通过 pdfcpu 命令工具,获取其他库用代码进行自动填充。

pdf_edit.png

使用 pdfcpu 可以检测一个 pdf 文件是否包含交互式表单。并通过命令行填充表单。

安装 pdfcpu

go install github.com/pdfcpu/pdfcpu/cmd/pdfcpu@latest

最神奇的是,这个居然给我自动安装上了 go 1.25。我本地的 go 版本总是被迫升级。

go: downloading github.com/pdfcpu/pdfcpu v0.11.1
go: github.com/pdfcpu/[email protected] requires go >= 1.24.0; switching to go1.25.7
go: downloading go1.25.7 (linux/amd64)
go: downloading github.com/hhrutter/pkcs7 v0.2.0
go: downloading github.com/hhrutter/tiff v1.0.2
go: downloading github.com/hhrutter/lzw v1.0.0
go: downloading golang.org/x/image v0.32.0
go: downloading golang.org/x/text v0.30.0
go: downloading github.com/mattn/go-runewidth v0.0.19
go: downloading github.com/clipperhouse/uax29/v2 v2.2.0

不包含交互式表单的情况

可以用官方提供这个 pdf 样例做测试:

https://github.com/pdfcpu/pdfcpu/blob/master/pkg/samples/form/demo/english.pdf

> pdfcpu form list test.pdf
installing user font:
Roboto-Regular
pdfcpu: no form available

包含交互式表单的情况

同样是输入如下命令:

pdfcpu form list english.pdf

可以看到结果如下图

pdf_form.png

每个字段有对应的名字。

自动对表单填充

新建一个 english.json 的文件,内容如下:

{
	"header": {
		"source": "english.pdf",
		"version": "pdfcpu v0.4.1",
		"creation": "2023-04-04 20:22:17 CET",
		"producer": "pdfcpu v0.4.1"
	},
	"forms": [
			"textfield": [
				{
					"name": "firstName",
					"value": "Horst",
					"locked": false
				}
			],
			"datefield": [
				{
					"name": "dob",
					"value": "31.12.1999",
					"locked": true
				}
			],
		}
	]
}

执行命令:

$ pdfcpu form fill english.pdf english.json tmp.pdf

就能实现自动填充,非常方便

如何将 word 转换为包含表单的 pdf

这个我没测试过,不知道是否可行,但是 gemini 说可以使用 LibreOffice Writer (直接导出)

  1. 用 LibreOffice 打开你的 Word 文档。
  2. 开启 “视图 -> 工具栏 -> 表单控件”。
  3. 在文档中插入“文本框”或“复选框”控件。
  4. 点击 “文件 -> 导出为 PDF”。
  5. 在弹出窗口中确保勾选了 “创建 PDF 表单”。

元宵节当头一棒,&quot;此小程序恶意注册,已被封号处理&quot;

2026-03-04 20:30:33

昨天刚经历了个人小程序不备案就无法打开的噩梦,个人小程序不备案无法访问,报错“该小程序仅支持由小程序开发团队体验,无法访问”。晚上又迎来暴击,提交小程序备案刚过预审,就被封号处理 🥲。前后也就半小时,开发了上百个小程序,还是第一次遇到这种情况。

此小程序恶意注册,已被封号处理

网上搜索了一下,好多人遇到了同样的问题。而且普遍是,根本没有真实用户访问过的情况下,因为备案完成前,根本没有新用户能打开小程序。那么何来的用户投诉。。。微信审核团队撒谎也不能认真点。。。

类似问题

没办法,客户着急用。我先临时把小程序的功能改造成网页 H5 版本,先让用户用着。好在客户比较好说话,也没有埋怨我。但是我真是有苦说不出,正月十五过节的晚上,刚家庭聚餐喝了个半晕状态,还要连夜改造小程序为网页版。这还好不是企业版小程序,否则交了 300 大洋还要被封禁,估计客户得跟我翻脸。

为何会被判定为恶意注册

在小程序后台,点击申诉按钮,才能看到违规的具体原因。给我的理由是:

违反规则《微信小程序平台运营规范》1.注册提交规范

1. 注册提交规范
1.1 提供给用户可以联络到开发者的链接或电子邮箱等有效联系方式。
1.2 提供给平台联络到开发者的管理员微信号,并保证该微信号真实有效。
1.3 你所提交的微信小程序,不得关联至你不具有完整合法权益或不具备完整授权的网站、应用程序、产品或服务等。
1.4 为保障平台和其他用户的安全、稳定,我们会在你提交微信小程序、运营微信小程序等全过程中,要求你提供相应的材料、进行相应的修改等补充和调整,你应当按照我们的要求协助我们进行审核,否则,将影响审核的结果。
1.5 微信鼓励开发者进行创新,不允许重复注册、提交2个及以上页面、内容、功能相同或同质化严重的微信小程序,以为用户提供多样化服务。同时,请避免注册或提交与已有的微信小程序相同或类似的微信小程序,保障微信小程序之间相互具有区别性和不可替代性,避免给用户造成混淆,影响用户体验,使微信小程序的账号资源得以合理使用。

看了一下这个规范,我感觉唯一可能有问题的是第五条。因为我的这个小程序功能确实是一套界面类似的功能,但是执行逻辑确实各不相同,因为不同版本的处理逻辑是不一样的。这个确实没办法,因为审核人员又不可能去看 js 逻辑代码。这以后就有点难搞了,想一套模版卖多份基本就没有活路了。而且,我提交的这个版本,还是用 AI 把 js 逻辑完全重写了一遍的版本,改动反而是最大的一版。。。我猜测微信应该是有一套自动截屏的系统,把小程序各个界面做截图备份,然后匹配相似度。因为这种判定不太可能是靠审核人员人工判定,大概率是靠系统比对后给出的建议。

规避方案

同时,也有一个客户给我转发了一个竞品的小程序,我当时还惊叹这么简单的功能为何花那么多精力在界面美化上。我现在想明白了,大概就是为了规避这个恶意注册的问题。其实大体思路:

  • 换不同的整体大背景图
  • 换不同的轮播图。那些批量卖的商城模版,你总不能都判定为功能类似吧。那淘宝和京东又有什么不同呢?
  • 先用模板开发,测试通过后,让 AI 重构界面,让界面看起来不一样。
  • 多个客户共用一套小程序,把处理逻辑放到服务器。每个人看到的都是自己特有的处理流程。
  • 干脆这种类型的功能不要做小程序了,全部转成网页版本。省去了注册,备案,每年交认证费的麻烦。

简单粗暴的处理方式

我感觉这是非常离谱的一个处理方式。因为没人会认真读你的条款。我做了这么多年的小程序开发,也是第一次见。但是,你不能因为一次违规就直接封号,为啥不能先拒绝发布,打回去重新开发修改呢?直接就封号也是真的任性。

个人小程序不备案无法访问,报错“该小程序仅支持由小程序开发团队体验,无法访问”

2026-03-03 21:59:54

之前个人小程序不备案还能继续使用,只是限制每天的使用人数。今天发现更严格了,不备案,直接没法打开了。如下图:

该小程序仅支持由小程序开发团队体验,无法访问

提示“该小程序仅支持由小程序开发团队体验,无法访问”,看来要跟企业小程序一样的严格了。刚开始,我没意识到是备案的问题,我以为只是刚发布,还没有更新到所有下载节点。登录到小程序后台看,才发现确实是没有备案的原因。

小程序未备案

你的小程序还未履行备案手续,发布上线后小程序将无法被搜索,仅限制小程序”成员管理”页中的微信用户调试体验使用,完成备案即可解除限制。真的太恶心了,我都备案了几十个小程序和网站了,每次都得重新来一遍,有这个必要吗?审核部门得多闲,非得反复看我的备案🙄哎,头痛,以后要想节约时间。就得先备案,然后同步开发小程序。主要是担心有的小程序没法过审核,先备案的话还要打回改名。