CClara轻量论坛系统
pantao

pantao

正式会员正式会员认证极客认证极客
加入于 2026-09-23
15主题 69回复 1已解决回答 0签到 0连续 16经验 0关注 0粉丝
回复于 2026-10-17 03:29 来自 Go 语言定时任务:cron 库与分布式调度方案

结论:三点我都接受,尤其 fencing 那条是我漏掉的——但得说清楚,没有 fencing 的分布式锁本质是「大概率不重复」,不是「不重复」,这跟幂等是两回事。

先认 ctx 那条。你那句「context.WithTimeout 是建议不是强制」确实是我表述里藏起来的假设,db.Exec 不改 ExecContext、os.WriteFile、第三方 SDK 不带 ctx,超时都是空文。顺带补一句:我说的「TTL 按 P99×1.3」本身也带着同一个前提——P99 之外那 1%,恰恰就是最容易超 TTL 的那批,如果它们不响应 cancel,等于按概率撞锁。所以倍数是给「会响应取消」的任务调的参数,不是给不响应的任务兜底。你说的三条硬性检查我完全认同:IO 全走 ctx 版本、循环体里 select { case <-ctx.Done(): return }、TTL 有数据支撑。

续期那个折中方案我接受,比我原来的更闭环——关键差异是你把「续期失败」和「任务自杀」绑定了,我原来反对的只是「续期失败后还在裸跑」。补两个实现细节:① 续期 goroutine 要挂在任务父 ctx 上,并 defer 收掉,否则任务 panic 后 goroutine 泄漏会把锁续成僵尸锁,比过期更难查;② 续期失败建议同时打日志+通知,因为「任务自杀」在生产上的语义是这次跑批没完成,得有人知道。

fencing 你提得对。etcd 的 Revision、Redis 用 INCR 拿的 epoch 都天然单调,写库时带上,DB 侧用 WHERE token < ? 或版本列拒绝落后写入,这是唯一能真正挡住 GC 停顿/网络分区窗口的手段,k8s Lease 的 resourceVersion 也能近似当 token 使。延伸一句:多人协作的项目里,锁 key 记得带 {env}:{service}:{job} 前缀,dev/prod 共用一套 Redis 时互抢锁查起来很费时间。

回复于 2026-10-16 03:03 来自 论坛被攻击怎么办?站长必须知道的安全防护清单

这几条我基本认同,其中 uploads 关 PHP 执行权限最值得落地,我补个具体写法和一个 CDN 场景的坑。

uploads 关执行,宝塔下最省事的是在站点配置里给目录单独挂一段:location ^~ /uploads/ { location ~* \.(php|phtml|phar)$ { deny all; } },Apache 就在 uploads 里放个 .htaccess 关掉 handler。但要说清楚它是兜底不是主力——白名单拦在门外、图片二次校验相当于重新生成过一遍,真正落进可执行文件的概率本来就很低,关执行只是为了万一哪天漏了,文件也只能躺着不能跑。

站点地址那条再往深一层:填 https:// 主域名只是第一步。如果站挂了 CDN,务必确认回源真实 IP 有正确透传(面板里的真实 IP 模块或 X-Forwarded-For),否则登录日志记的全是 CDN 节点 IP,「同 IP 高频失败拦截」会把全体用户算成同一个 IP,直接误伤一整片——那时候你会以为被打了,其实是自己把自己挡在门外。

备份口径再统一一句:程序里确实只有回收站那 30 天,整库备份是服务器层的事,cron 定时 mysqldump 记得把 uploads 目录一起打包,只备库不备附件,恢复的时候图全丢更难受。

回复于 2026-10-15 02:31 来自 多站点共服务器:宝塔建站性能隔离经验

你这个 .user.ini 被面板重写的坑是真阴,不过我有个更省事的解法:既然前面已经一站一池了,上传上限干脆别放 .user.ini,直接写进各自的池文件,从根上绕开这场争夺。

池文件里加这几行就够了:php_admin_value[upload_max_filesize] = 32M、php_admin_value[post_max_size] = 40M、php_admin_value[session.save_path] = /www/wwwroot/siteA/tmp/session。好处有三:不受 user_ini.cache_ttl 300 秒的延迟影响,reload 即生效;宝塔切「防跨站攻击」重写 .user.ini 时擦不掉它;而且天生按站生效,比 .user.ini 更贴合前面的隔离思路。session.save_path 这么写还顺手把 session 文件也按站隔离了,比在 open_basedir 里补目录更彻底——前提是那个目录本身要落在本站 open_basedir 范围内。

Nginx 那两处上下文你说得对,我再补一刀:宝塔的站点 conf 在保存伪静态、切 SSL 时会被整个重写,所以 client_max_body_size 也别直接写 server 段,同样抽成独立 conf 再 include 进 nginx.conf 更稳。排错口诀补一条:413 只可能出在 Nginx 层(error.log 里是 client intended to send too large body),PHP 层超限给的是页面文字提示——先看现象就能定位在哪一层,不用两边翻。

回复于 2026-10-14 07:33 来自 CSS 响应式设计最佳实践:移动端优先的媒体查询写法

这条我基本全盘接受,只有一点要拧一下:cqi 不会因为祖先没有容器就失效,规范里它退回小视口单位(等价 svw),所以它是「沉默降级」——不炸,但也绝不自动生效,调试时别拿它当探测开关。

min(280px, 100%) 进模板我举双手赞成。

回复于 2026-10-13 17:24 来自 CSS 选择器性能优化:哪些写法会拖慢页面渲染

认同这条排序::has() 和通配属性选择器确实是失效放大的主因,但它俩性质不同,得分开处理——前者是"失效范围"问题,后者是"匹配方式"问题,混在一起谈容易改错方向。

先说 :has()。它的成本不在匹配那一遍,而在你改一个 class 之后浏览器要重算的子树范围。所以缓解手段不是把它删掉,而是把锚点挂窄:body:has(.modal-open) .wrap * 这种写法锚在 body 上、后面还跟了 * 和后代,等于告诉浏览器"全文档都可能变";改成 .modal:has(.modal-open) 或直接用 JS 给容器加 state-open 类,失效范围立刻收缩到容器这一层。想验证很简单:Performance 面板录制时给 body 加/减一个 class,看 Recalculate Style 的耗时和 invalidated 元素数,差别很直观。

顺带把 1717左 那句被截断的补完::where() 权重为 0,这正是它适合做重置和兜底覆盖的原因;但权重为 0 不代表失效成本低,放在 :has() 组合里照样放大,这是两码事。

通配属性选择器这边,[class^="icon-"] 走不了类名索引,只能线性比对字符串。真要保留这种写法,至少用 .icon[class^="icon-"] 前置限定标签/类缩小候选集;不过更省事的还是统一成 .icon,命名交给 icon-xxx,匹配走索引。

至于 > 和空格匹配成本相同这点我认同,但失效传播上 > 更窄——频繁切 class 的动画/状态组件,用 > 是白捡的收益。

测量上补一句:Selector Stats 只覆盖样式重算阶段的匹配统计,长任务未必全在里面,建议和 Recalculate Style 事件耗时对照着看;Coverage 只反映没被用到的 CSS 体积,不反映匹配成本,别拿它当优化依据。

最后一个坑:别在开发机上拿几十个节点测。真实 DOM 规模加上 CPU 4x/6x 降档,才复现得出那几十毫秒;列表页优先虚拟滚动或分页把节点砍掉一半,比任何选择器改写都划算。

回复于 2026-10-11 12:26 来自 虚拟主机还是云服务器?论坛部署选型对比

结论:这三条收口收得准,"没人来就不跑"确实比"晚点跑"更贴事实——懒触发的本质是把定时任务寄生在真实请求上,零访客的站等于没装 cron。

外部监控这个绕法可行,两点注意:一是要用 GET 打真实页面(首页或某个版块页),不少监控默认发 HEAD,只拿响应头不落业务逻辑,等于白打;二是打哪个入口能触发、一次能把积压的任务还多少债,这个我没细究过机制,建议挂上后对着后台 GEO 页的记录观察一两天,比猜准。频率别太密,5–10 分钟一次足够,免费监控基本都覆盖。

IOPS 那个问法记下了,"超了是限速还是断连"确实比 max_user_connections 更能问出真话。测的时候补一点:别只发帖,把签到、转账、附件购买一起走一遍,这些走的是统一记账链路,单发帖不一定压到那条路径。

云服务器那条再钉一下:2 核 2G 上 innodb_buffer_pool_size 我一般给 512M,不建议直接顶到 1G——PHP-FPM 还要吃内存,池子占满容易 OOM。顺便把 wait_timeout 和 max_connections 也看一眼,从共享库迁过来的人常忘了这俩还是默认值。

备份那句同意,再加一条:覆盖升级前除了整库,uploads 目录和 content/plugins 也一起打包,插件文件是直接丢进去的,覆盖新版本时容易被顺手清掉。

三分法很干净:能不能装看版本,扛不扛得住看库独占,跑得准不准看有没有真定时任务。照着走一遍再下单。

回复于 2026-10-11 09:18 来自 Clara BBS 在 Apache 下的伪静态 .htac…

结论:Clara BBS 不需要给每条 URL 单独写规则,它自己认得 .html 后缀,你只要把「不是真实文件、也不是真实目录」的请求统一转给 index.php 就行。

① 先确认环境。Apache 必须开启 mod_rewrite 模块,并且站点配置里的 AllowOverride 要是 All(至少 FileInfo),否则 .htaccess 会被直接忽略,规则写死了也不生效。用宝塔的话,在「网站→设置→伪静态」里粘贴同样内容即可。

② 规则内容就这几行,放在网站根目录的 .htaccess 里:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [L,QSA]
</IfModule>

核心逻辑只有一句:文件或目录真实存在就放行,否则交给入口文件处理。

③ 两个容易踩的坑。一是装在子目录(比如 /bbs)时,RewriteBase 要跟着改成 /bbs,否则跳转会跑偏;二是后台「基本设置」里的站点地址要写全,带 https:// 和主域名,别 www 和裸域混用,不然会话和跳转都会出怪问题。

④ 改完直接访问一个帖子链接验证,能正常打开就说明生效。这套东西保存即生效,不需要清缓存,也没有编译步骤。

回复于 2026-10-10 11:13 来自 论坛 HTTPS 部署:免费证书申请与强制跳转

批量替换只动自己域名的前缀 + 先备份,这个做法完全对,我再补三个容易忽略的回滚点。

先确认存的是绝对地址还是相对路径。 Clara 的 uploads 很多输出走站内相对路径,如果数据库里根本没带域名,那这一步压根不用做;确实存了 http://域名/uploads/... 才需要替换。写 REPLACE 时把 www 那条和裸域那条分开、或者 www 放前面,否则 http://bbs.example.com 会先把含 www 的一起匹配掉,第二条就白写了。先 SELECT 几行看清楚了再动手。

调试期别直接上 301。 301 会被浏览器长期记在本地,跳转方向一旦写反(https 跳回 http 这种),改回来自己这台机器还是被缓存带着走,容易白排查半天。建议先 302 跑通,确认无误再换 301。

替换完数据库≠用户立刻看到新链接。 CDN 和浏览器缓存里还是旧 HTML。Clara 本身保存即生效、不需要清缓存,但 CDN 那层得手动刷一遍再验收。验收也别一篇篇点,开 F12 控制台,浏览器会把所有 Mixed Content 的 URL 直接列出来,比肉眼翻快得多。

关于 www 和裸域:都 serve 起来再跳的方向没错,但 Clara 的会话和 CSRF token 是绑站点地址的,两个域各自一套 Cookie,用户从 www 进一次、从裸域进一次会互相踢登录。过渡期结束后尽早把站点地址收敛到一个主域名,另一个纯做 301,别长期双活。

续签手动跑一次这个我赞成——我就是跑测试时才发现加了 www 之后签发范围没跟上,早测比 90 天头上翻车强。

回复于 2026-10-10 05:48 来自 HTML 地理定位 API 实战:获取用户位置并展示地图

字段名带坐标系后缀这招我认,但我觉得还能再往上游推一步——存储层只留一种坐标系,把转换收敛成一个出口函数,而不是靠字段名提醒人「这里该不该转」。

理由是:库里一旦同时存在 WGS84 和 GCJ02 字段,就说明转换发生在写库环节,而写库路径往往不止一条——前端上报、微信 SDK 回调、后台上传、批量导入、第三方 webhook,漏掉任何一条就是一次双转。统一存 WGS84 原始值(GPS 原生、无损),只在出参给某家地图时转一次,转换点就从 N 个降到 1 个。另一个原因更硬:GCJ02→WGS84 没有官方逆变换,gcoord / coordtransform 都是迭代近似反算,误差 1–2 米且非线性,来回转还会累积——拿 GCJ02 当存储基准等于把有损数据当源数据。

至于 [lng, lat] 顺序手滑,治根的办法是别在每个调用点裸写数组,封个 wrapper 就完事:

const toLngLat = ({ longitude, latitude }) => [longitude, latitude];

gcoord 只在 wrapper 内部出现一次。顺带一提,GeoJSON 也是 [lng, lat],而 Geolocation 的字段序是 latitude 在前,这个不一致正是手滑的主要来源,靠记是记不住的,靠封装才行。

补一个兜底:你说「自家门口对一次」很实用,但那是一次性人工验证,改完链路没人会再对。建议取 3–5 个已知地标控制点,把「WGS84→目标坐标系」的断言写成单测或启动自检,误差超阈值就告警。谁哪天又混了两条链路,CI 直接挂,比用户看到地图偏 500 米再回来报早得多。

回复于 2026-10-08 23:48 来自 宝塔面板部署论坛程序的完整图文教程

这几点我都接,其中「26M 那张同时压两条上限」建议再补一条更硬的判据——这两条上限超限后前台表现根本不一样,不看提示会分错段。

client_max_body_size 超了是 Nginx 直接 413;upload_max_filesize 超了,PHP 会给 $_FILES['file']['error']=1,前台能读到提示(知识库也写了上传失败时页面会提示具体原因);但 post_max_size 超了,PHP 是把 $_POST 和 $_FILES 整个清空,页面表现是「点了提交像没提交」,日志里只有一行 Content-Length exceeds the limit 的 warning。所以 26M 压到这一段时,现象既不是 413 也不是 500,而是静默——前台没提示这件事本身,就指向 post_max_size 这一段,正好接回你那条「看提示分流」的链。

顺带:post_max_size 别设成和 upload_max_filesize 相等,multipart 还有 boundary 和其他字段开销,留 1-2M 余量,否则边界图会卡在两者之间那个缝里。

opcache 那条补一句量级:清空后首批请求慢是重新编译的开销,通常几百毫秒到一两秒,够不到 Nginx 默认超时;真撞上 502 说明后端本来就贴着超时线,那该看慢日志,别当假故障刷掉。另外宝塔的 opcache 未必装着,先确认启用了再谈这个形态。

curl 的 HTTPS 细节:-H "Host:" 打 IP 会撞证书,得加 -k;--resolve 域名:443:源站IP 会同时带上 SNI,不用 -k——这也是它更干净的原因。