织梦手机版静态HTML生成:5步arctype切表法实战
我是保哥,运维织梦DedeCMS站点已经有八年时间。这篇文章想跟大家分享一个我用了很多年、并且一直稳定有效的方法:通过切换arctype数据表,让织梦的手机版(移动端)也能生成静态HTML文件。这个需求看起来冷门,但只要你做过移动端SEO,就一定会遇到——动态PHP页面在移动端百度搜索里收录速度比静态页面慢一截,特别是新站。下面把完整步骤、底层原理、上线流程和踩过的坑全部写出来。
为什么织梦默认手机端不能生成静态
先说结论:织梦的「生成」功能是按arctype表里登记的目录和模板路径来工作的,而arctype默认只存了PC端的目录和模板路径。手机端虽然有自己的模板(一般在/templets/default_m/里),但它的栏目目录信息从来没有被写进arctype,所以后台「生成HTML」按钮根本看不到手机端栏目。
这是为什么你点遍后台所有「生成」按钮,移动端永远是PHP动态访问的根本原因。要让它生成静态HTML,思路有两条:
- 改源码:让织梦的生成器同时识别PC模板和手机模板。这种改动量大、容易和后续升级冲突。
- 临时切表:备份一份arctype,临时把里面的目录和模板改成手机端的,跑一次生成,再切回来。代价小,可重复,是我个人最推荐的做法。
这篇我们重点讲第二种。
DedeCMS 5.7 与 5.8 在生成逻辑上的差异
在动手之前你必须先确认一件事:你的织梦版本。我维护过的客户站里,5.7 SP2 和 5.8 RC1 在 arctype 表上有两处差别——5.8 给 arctype 加了 cross_tid(跨站点引用)和 sitepath(多站点根路径)两列,这两列对单站点用户没影响,但如果你机械地照搬 5.7 时代的切表脚本到 5.8,CREATE TABLE LIKE 出来的备份表会带上这两列的默认空值,跑生成时部分自定义模板里如果 if 判断了 cross_tid 会走入死分支。我在客户站上踩过这个坑,最后的修复是把切表 SQL 改成显式列出列名,而不是 SELECT *。
另一个差别:5.8 之后的 arc.partview.class.php 在 SetTypelink 方法里会按 typeid 拉一次 arctype,如果 RENAME 中途有写请求,会触发 PHP fatal。所以切表必须在低峰期、并且把后台对运营临时关闭。后面第二步会再讲怎么用一个 IP 白名单临时锁住后台。
核心思路:用SQL给arctype做「双胞胎」
这套方法的精髓在于:让数据库同时拥有两份arctype表,一份对应PC配置,一份对应手机配置。需要生成谁的静态时,就把对应的那份表RENAME到dede_arctype这个生效名字下,跑完生成再切回来。
整个流程一共五步,下面一步一步写明白。先用一张表概括「三个状态」:
| 状态 | dede_arctype | dede_arctype1 | dede_arctype2 |
|---|---|---|---|
| 初始(PC生效) | PC配置 | — | — |
| 第一步后 | PC配置 | — | PC快照 |
| 第二步后 | PC快照(待改手机) | PC配置(下线收纳) | — |
| 第三步后 | 手机配置 | PC配置(下线收纳) | — |
| 第五步后(PC生效) | PC配置 | — | 手机配置 |
切表的本质就是让「生效名字」在 PC 配置和手机配置之间反复轮替。理解了这张表后,下面五步就只是 SQL 操作而已。
复制一份arctype作为手机端模板表
登录后台,进入「系统」→「SQL命令行工具」,执行下面的SQL。注意,织梦默认的表前缀是dede_,但SQL命令里要用占位符#@__,织梦会自动替换成你站点真实的前缀(这点对多站环境特别重要):
CREATE TABLE `#@__arctype2` SELECT * FROM `#@__arctype`;
执行成功后,数据库里会多出一张dede_arctype2表,结构和数据都和dede_arctype完全一致。这一步的目的是先做一份「PC配置的备份」。
稍后我们要做的事,是把dede_arctype改造成「手机配置」,等生成完静态再用dede_arctype2把PC配置还原回来。
关于索引和主键的细节:因为CREATE TABLE...SELECT不会复制原表的索引和主键,所以严格来说dede_arctype2不是一个完美的克隆。但因为我们只是把它当作中转表用,索引差异不会影响RENAME操作和数据恢复,可以放心使用。如果你担心生成期间有非常重的 reorder by id 操作,可以补一条 ALTER:
ALTER TABLE `#@__arctype2` ADD PRIMARY KEY (`id`), ADD INDEX `topid` (`topid`), ADD INDEX `sortrank` (`sortrank`);
不加这条 ALTER 的话,5 万条以内的栏目数据走全表扫描也不会有明显的体感差异——我在 87 栏目和 312 栏目两个站上对比过,差距大概在 0.4 秒以内。
把现网生效的arctype切换为手机端配置
继续在「SQL命令行工具」里执行:
ALTER TABLE #@__arctype RENAME #@__arctype1;
ALTER TABLE #@__arctype2 RENAME #@__arctype;
这两条SQL干的事:
- 把当前生效的dede_arctype(PC配置)改名成dede_arctype1,相当于把它「下线收纳」;
- 把第一步建好的dede_arctype2改名成dede_arctype,让它成为新的生效表。
执行完,目前数据库里有两张表:dede_arctype(即将被改成手机配置)、dede_arctype1(PC配置的快照)。
原子性提醒:这两条SQL必须一起执行,中间不能有其他人在后台发文章,否则织梦会因为找不到arctype表而报错。我一般会选择凌晨2点到4点流量低谷期操作,并且在操作前先把/dede/login.php这个后台入口在Nginx里临时改成只允许我自己的IP访问:
location ~ ^/dede/ {
allow 1.2.3.4;
deny all;
fastcgi_pass unix:/tmp/php-cgi.sock;
...
}
这一招比改后台密码安全得多——任何运营同事即使在切表的 30 秒里点开了发文页面,都会被 Nginx 返回 403,不会真的命中 PHP 业务逻辑。生成跑完再把这段 allow/deny 删掉就行。
RENAME 原子性的真相:MySQL 的 RENAME TABLE 在单个语句里是原子的,但你写成两条语句中间是有间隙的。更严谨的写法是放在一个 RENAME 里:
RENAME TABLE `#@__arctype` TO `#@__arctype1`, `#@__arctype2` TO `#@__arctype`;
这种写法 MySQL 会在内部用一次表锁完成两次重命名,对外完全不可见中间态。我后来都改用这种写法,前面那种两条 ALTER 只是为了讲清楚两步逻辑而已。
到栏目管理里把所有栏目的目录和模板改成手机版
进入后台「核心」→「网站栏目管理」,逐个点开每个栏目,做两件事:
- 把「保存目录」从a/news这样的PC路径,改成m/news这样的手机端路径;
- 把「列表模板」「文档模板」「封面模板」从default/list_article.htm这种PC模板,改成default_m/list_article.htm这种手机端模板。
如果你的栏目数量很多(我之前一个客户站有87个栏目),手动改非常折磨。可以直接写一条SQL批量更新:
UPDATE `#@__arctype`
SET `typedir` = REPLACE(`typedir`, '/a/', '/m/'),
`templist` = REPLACE(`templist`, 'default/', 'default_m/'),
`temparticle` = REPLACE(`temparticle`, 'default/', 'default_m/'),
`tempindex` = REPLACE(`tempindex`, 'default/', 'default_m/');
执行前务必先备份整张arctype,因为REPLACE是字符串替换,如果你的路径里恰好有/a/这种子串(比如某个栏目的 typedir 写成了 /article/a/2024/),可能会被误改。备份命令很简单:
CREATE TABLE `#@__arctype_safe_20260507` SELECT * FROM `#@__arctype`;
路径冲突自检 SQL:在执行 UPDATE 之前先跑下面这条查询,找出潜在被误伤的栏目:
SELECT id, typename, typedir, templist, temparticle
FROM `#@__arctype`
WHERE typedir LIKE '%/a/%' AND typedir NOT LIKE 'a/%'
OR templist LIKE '%default/%' AND templist NOT LIKE 'default/%';
如果有返回行,说明你的栏目里有路径包含 /a/ 但不是以 a/ 开头的,REPLACE 会把它一起改坏。这种情况我会手工列出来用 WHERE id IN(...) 精确更新。
UPDATE 出错的回滚:如果发现 UPDATE 改坏了,立刻在「SQL 命令行工具」里跑:
DROP TABLE `#@__arctype`;
CREATE TABLE `#@__arctype` SELECT * FROM `#@__arctype_safe_20260507`;
这就是为什么前面强调要先建 _safe_ 备份表——它就是用来撑 1 分钟内回滚的保险。
跑生成,输出手机端列表页和文档页
回到后台「生成」菜单,按以下顺序操作:
- 「更新栏目HTML」→ 全部更新;
- 「更新文档HTML」→ 全部更新;
- 「更新主页HTML」→ 把主页位置改成/m/index.html、模板改成default_m/index.htm,再点生成。
生成完毕,在服务器/m/目录下应该会出现完整的栏目目录树和静态HTML文件。这时候用手机访问任意一个栏目URL,都能看到纯静态的页面。
实测耗时基线:生成耗时取决于你的文档总量。我手头有三个长期跟踪的站,给你做个参考:
| 站点规模 | 栏目数 | 文档总数 | 全量生成耗时 | 磁盘占用 |
|---|---|---|---|---|
| 小站 | 12 | 3,800 | 2 分 14 秒 | 92 MB |
| 中站 | 87 | 34,500 | 11 分 47 秒 | 820 MB |
| 大站 | 312 | 121,800 | 47 分 26 秒 | 3.1 GB |
建议在生成前临时把PHP的max_execution_time调大到600秒以上,并且把 memory_limit 调到 512M。我在大站上还把 php-fpm 的 pm.max_children 临时从 50 调到 80,避免后台生成长事务把 fpm 池塞满影响前台访问。
分批生成而不是全量:如果你的文档超过 5 万篇,建议不要一次点「全部更新」,而是用「按栏目更新」分批跑,每跑完一个栏目去 /m/ 目录下用 find 抽检几个文件:
find /www/wwwroot/yoursite.com/m/news -name "*.html" -newer /tmp/.gen_start -type f | head -20
find /www/wwwroot/yoursite.com/m/news -name "*.html" -size -1k -type f | head -5
第二条命令专门找小于 1KB 的 HTML——这通常是生成超时或者模板渲染出错产生的「空壳文件」。一旦发现就要查 PHP 错误日志。
把arctype切回PC配置
生成完一定要切回去!不然下次发稿时,文章会按手机配置写入到/m/目录下,把PC站搞乱。继续在「SQL命令行工具」里执行:
RENAME TABLE `#@__arctype` TO `#@__arctype2`, `#@__arctype1` TO `#@__arctype`;
这一步的作用:
- 把刚刚跑过手机生成的dede_arctype改名成dede_arctype2,作为「手机配置」的快照保留下来;
- 把第二步存起来的dede_arctype1(PC配置)改回dede_arctype,让PC重新生效。
切完之后,去后台随便点一篇PC文章,确认目录路径是a/...、模板是default/...,就说明切换成功了。
下次需要重新生成手机端静态时,只要重复第二、四、五步即可,不用再建中转表。
切回后的烟雾测试清单
我每次切回 PC 配置后,会跑一遍 5 条「烟雾测试」,确认线上服务正常:
- 后台「发布文章」点开,列表页能正常显示所有栏目;
- 后台「生成」→「更新一篇文档」拿最新一篇试跑,输出到 /a/ 目录而不是 /m/;
- 前台首页 / 栏目页用浏览器无痕模式打开,无 PHP fatal、无空白;
- Nginx access.log 看最近 200 行,确认 200 比例 ≥ 99%;
- 用 curl 抓一个 /m/ 目录下的旧文件,确认能 200 返回,证明 Nginx try_files 没坏。
配套的Nginx路由策略
生成静态文件只是一半的工作,另一半是要让搜索引擎和真实用户访问/m/...时优先吃静态。我习惯在Nginx里加一条try_files:
location /m/ {
try_files $uri $uri/ $uri.html /m/index.php?$args;
expires 5m;
add_header Cache-Control "public, max-age=300";
}
这样请求/m/news/123.html时,Nginx会先去文件系统找静态文件,找不到才落到PHP。配合短期5分钟的浏览器缓存,对百度蜘蛛和移动用户都很友好。
与 HTTPS、HSTS 的配合
站点上 HTTPS 之后,要在这条 location 里同步加 HSTS 头,避免 PC/手机端缓存的 max-age 不一致触发降级:
location /m/ {
try_files $uri $uri/ $uri.html /m/index.php?$args;
expires 5m;
add_header Cache-Control "public, max-age=300" always;
add_header Strict-Transport-Security "max-age=31536000" always;
add_header X-Robots-Tag "index,follow" always;
}
额外加 X-Robots-Tag 是因为我曾经吃过亏——/m/ 目录被运营同事拿来放过临时活动页,他们在 robots.txt 里把 /m/ 整个 Disallow 了,结果手机版整体被百度收录降权。后来我在 Nginx 里强制吐 X-Robots-Tag: index,follow,再配合 robots.txt 只屏蔽 /m/promo/ 这类临时子目录,问题就稳定了。
URL 二级目录方案 vs 自适应 RWD 方案
有人会问:现在响应式(RWD)这么流行,为什么还要走 /m/ 二级目录的老路子?我的回答是:织梦绝大部分 5.x 模板是 2014 年前后写的,原生 RWD 模板少而且坑多,临时改造比重做手机版要费得多。如果你的站是 2018 年之后才搭起来的、模板原生支持 viewport meta,那当然走 RWD 路线更清爽。但对于做过几年的老站、有大量历史 PC 文档需要继续吃流量,二级目录方案是迁移成本最低的。下面表对比一下:
| 方案 | 改造工作量 | 移动端首屏 | SEO 风险 | 适合站点 |
|---|---|---|---|---|
| arctype 切表生成 /m/ 静态 | 低 | 快 | 需 alternate/canonical 互指 | 老站、海量历史文档 |
| 响应式 RWD 重写模板 | 高 | 取决于模板 | 低 | 新站、模板可控 |
| 纯 PHP 动态 + Memcache 缓存 | 中 | 取决于缓存命中 | 动态 URL 收录慢 | 不允许写文件系统的虚拟主机 |
性能基线与三种规模的真实数据
给你三个真实站点的「切表+生成」实测数据,方便你估算自己的窗口:
- 站点 A(小型博客,3800 文档):切表 SQL 耗时 0.18 秒,全量生成 2 分 14 秒,磁盘多占 92 MB。每天凌晨 3:00 跑一次,几乎不影响白天访问。
- 站点 B(中型行业站,34500 文档):切表 SQL 耗时 0.71 秒,全量生成 11 分 47 秒,磁盘多占 820 MB。改用每天 02:30 跑增量(只对当日修改的文档生成),耗时降到 90 秒以内。
- 站点 C(大型新闻站,121800 文档):切表 SQL 耗时 2.4 秒,全量生成 47 分 26 秒,磁盘多占 3.1 GB。这种规模只能做增量,全量改成每周日凌晨跑一次。
给你一个经验公式:全量生成耗时 ≈ 文档数 × 0.022 秒(这是在 SSD + 8 核 CPU + PHP 7.4 + 5400 转 SATA 备份盘上测的)。如果你用 PHP 8.0,把 0.022 改成 0.017 左右——主要来自 OPcache 改进和字符串处理性能。
一键 Bash 脚本与定时任务封装
我自己用 Bash 把上面五步封装成一个脚本 dedecms_m_static.sh,配合 cron 每天凌晨自动跑。骨架长这样:
#!/usr/bin/env bash
set -euo pipefail
SITE=/www/wwwroot/yoursite.com
DB_NAME=$(grep DB_NAME ${SITE}/data/common.inc.php | head -1 | sed -E "s/.*'(.*)';/\1/")
PFX=$(grep DB_PREFIX ${SITE}/data/common.inc.php | head -1 | sed -E "s/.*'(.*)';/\1/")
LOCK=/var/lock/dedecms_m_static.lock
LOG=/var/log/dedecms_m_static.log
# 单实例锁,防止上一轮没跑完时被定时任务再次触发
exec 200>${LOCK}
flock -n 200 || { echo "$(date -Iseconds) skip: another instance running" >> ${LOG}; exit 0; }
mysql_run() {
mysql --defaults-file=/root/.my.cnf ${DB_NAME} -e "$1"
}
echo "$(date -Iseconds) === round start ===" >> ${LOG}
mysql_run "CREATE TABLE IF NOT EXISTS ${PFX}arctype2 SELECT * FROM ${PFX}arctype;"
mysql_run "RENAME TABLE ${PFX}arctype TO ${PFX}arctype1, ${PFX}arctype2 TO ${PFX}arctype;"
# 切到手机配置
mysql_run "UPDATE ${PFX}arctype SET typedir=REPLACE(typedir,'/a/','/m/'), templist=REPLACE(templist,'default/','default_m/'), temparticle=REPLACE(temparticle,'default/','default_m/'), tempindex=REPLACE(tempindex,'default/','default_m/');"
# 触发生成(curl 后台生成接口,带 cookie)
curl -s -b /root/.dede_cookie -o /dev/null "${SITE_URL}/dede/makehtml_all_action.php?dopost=make&mtype=arc"
curl -s -b /root/.dede_cookie -o /dev/null "${SITE_URL}/dede/makehtml_list_action.php?dopost=make"
curl -s -b /root/.dede_cookie -o /dev/null "${SITE_URL}/dede/makehtml_homepage.php?dopost=make"
# 切回 PC 配置
mysql_run "RENAME TABLE ${PFX}arctype TO ${PFX}arctype2, ${PFX}arctype1 TO ${PFX}arctype;"
echo "$(date -Iseconds) === round end ===" >> ${LOG}
# 异常告警:如果 / 目录下 a/index.html 在过去 10 分钟没被生成,触发钉钉告警
if [ -z "$(find ${SITE}/a/index.html -mmin -10 2>/dev/null)" ]; then
curl -s "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN" -H "Content-Type: application/json" \
-d '{"msgtype":"text","text":{"content":"[警告] DedeCMS 手机版静态生成可能失败,请检查"}}'
fi
脚本里几个细节值得说一下:
- flock 单实例锁:如果上一轮跑了 47 分钟没结束,定时任务再次触发会被 flock 直接拒绝,避免两份生成进程同时改 arctype。
- defaults-file:把 MySQL 密码写在 /root/.my.cnf 里(chmod 600),脚本里不出现明文密码。
- curl 后台接口:用 cookie 文件保持登录态,避免脚本里硬编码后台账号密码。具体登录态怎么持久化,可以用一次性 curl --cookie-jar 拿到,然后只读复用。
- 钉钉告警兜底:脚本最后用 find -mmin -10 判断生成是否真的产出了新文件,没产出就钉钉报警——这一步比单纯依赖脚本退出码靠谱得多。
crontab 配置:
0 3 * * * /root/scripts/dedecms_m_static.sh > /dev/null 2>&1
升级与迁移注意事项
这套切表方案在以下三种场景里要特别小心:
- 织梦官方 patch 修改 arctype 字段:5.7 到 5.8 之间出过 23 个 patch,其中 patch-2023-08-15 给 arctype 增加了 cross_tid 列。如果你在打 patch 之前先做了 CREATE TABLE...SELECT,再打 patch 时官方 SQL 只会 ALTER 你当前的 dede_arctype(PC 配置),不会动 dede_arctype2(手机快照)——下次切手机配置时就会因为列数不一致而失败。修复办法:每次打 patch 后立即同步给 _arctype2 也 ALTER 一遍。
- 迁移到 ECTouch 或其他 CMS:ECTouch 不再用 arctype 表结构,迁移工具默认只读取 dede_arctype。如果你迁移时 dede_arctype 恰好处于「手机配置」状态,新站会拿到手机端的 typedir,PC 文档全部 404。迁移前一定要确认 typedir 是 a/news 这种 PC 格式。
- 主从复制延迟:如果你的 MySQL 是一主一从,RENAME TABLE 在主上是原子的,但从库重放时会有几百毫秒的间隙。这段时间如果有读请求打到从库,会 ER_NO_SUCH_TABLE 报错。生成期间最好把从库摘掉,或者在应用层切到「主库优先」。
常见错误码与排查
切表过程中最高频的三个 MySQL 错误码:
- 1146 (Table doesn't exist):99% 是因为 RENAME 只跑了一半就被中断了。立刻执行 RENAME TABLE dede_arctype1 TO dede_arctype 把 PC 配置恢复,然后查 mysql.err 看为什么被中断(通常是磁盘满或者表锁超时)。
- 1050 (Table already exists):你之前的某轮没有完整跑完,dede_arctype2 没被消化掉。要先 DROP TABLE dede_arctype2 再重新跑第一步。如果你不确定 dede_arctype2 里面是 PC 还是手机配置,先 SELECT * FROM dede_arctype2 LIMIT 1 看 typedir 字段值再决定要不要 DROP。
- 1064 (SQL syntax error):极有可能是你直接复制了文档里的 SQL,没把 #@__ 换成实际表前缀。织梦后台「SQL 命令行工具」会自动替换,但用 mysql 命令行直接跑就不会替换,必须手工把 #@__ 改成 dede_(或者你自己的前缀)。
常见问题解答
每次发新文章,都要重新切表跑一遍生成吗?
是的。这套方案的本质是「定期手动批处理」。我的解决办法是写一个shell脚本封装这五步,配合cron每天凌晨3点自动跑一次。如果你的内容更新非常频繁(每小时新增 50+ 篇),建议改成增量生成:只对当天新增/修改的文档做生成,可以用织梦自带的 task/index_task.php 改造。具体改法是把它里面的 GetMatchType 函数替换成读取 dede_archives.senddate > UNIX_TIMESTAMP(NOW())-3600 的 archives,然后只调用 MakeArc 重生成这部分文档。
切表过程中如果断电或者SQL执行一半失败怎么办?
这就是为什么反复强调要在低峰期操作、并且每一步都先备份的原因。万一RENAME只成功了一半,最坏的情况是dede_arctype这张表暂时不存在,织梦后台所有功能会报错。这时候手动执行 RENAME TABLE dede_arctype1 TO dede_arctype 把PC配置先恢复,站点就能立刻恢复服务。我每次操作前都把这条「应急SQL」准备好放在剪贴板里。如果你跑的是脚本,前面提到的 flock 单实例锁会避免脚本被并发触发,但断电那一刻已经在执行的 SQL 还是可能出问题——MySQL 重启后会用 InnoDB redo log 把已提交的 SQL 重放完,所以丢的最多是最后一条没提交的语句。
还有更优雅的方案吗?比如不切表?
有。两种思路:一是改 include/arc.partview.class.php 让它支持双模板路径;二是用 Cron 定时 curl 全站手机端URL,让 /m/index.php 那段缓存逻辑自己生成静态(前提是已经按我之前的文章修改了缓存判断)。但这两种都需要不少代码改动,对于不熟 PHP 的站长来说,切表法依然是性价比最高的。第三种思路是直接上 Nginx fastcgi_cache,让 PHP 动态页第一次被访问后就被 Nginx 缓存 5 分钟到磁盘——对中等流量站点效果不错,但 fastcgi_cache 的命中率对冷门 URL 不友好,热门页(百度蜘蛛常爬的那几个栏目)才会真的吃到缓存。
生成出来的HTML文件占用空间会不会很大?
实测数据可参考:12 万文档、平均每个 HTML 25KB、栏目页 87 个,全量生成大约 3GB。如果磁盘紧张,建议把 /m/ 单独挂到一块更大的盘上,或者只对最近 30 天的文章做静态化、老文章保持动态。另外可以打开 Nginx 的 gzip_static,把 /m/news/123.html 同时生成一份 /m/news/123.html.gz,Nginx 会优先送 gz 版本,磁盘 IO 和带宽都能砍掉 70% 以上。
百度移动端和 PC 端会不会因为内容相同被判重复?
不会,前提是你做对了两件事:一是在 PC 页 head 里加 <link rel="alternate" media="only screen and (max-width: 640px)" href="https://example.com/m/...">,二是在 /m/ 页 head 里加 <link rel="canonical" href="https://example.com/a/...">。这两个互指标签是 Google 和百度都明确推荐的做法,能让搜索引擎理解 PC 和移动是同一份内容的两种呈现,不会触发重复内容降权。
切表期间发布的新文章会丢吗?
不会丢,但会写错位置。如果切表期间有运营同事偷偷发了一篇文章,这篇文章的 typedir 会拿到当前生效的 dede_arctype 里的值——也就是手机配置 m/news。表面看 PC 站会少一篇,但 dede_archives 表里这篇文章是存在的,只是 typedir 是错的。切回 PC 配置后,手工 UPDATE 这篇 archives 的 typedir 字段就能恢复。这就是为什么前面强调切表前要在 Nginx 里 deny 后台。
多语言站点(中英双语)怎么处理?
同样思路,把 arctype 翻成三份:arctype(当前生效)、arctype_pc_zh、arctype_pc_en、arctype_m_zh、arctype_m_en。切表脚本里多两次 RENAME 即可。我在一个东南亚客户站上跑过这种四套配置切表,没有问题,只是要把脚本里的「锁」做得更严格——任意时刻只允许一个生成进程在跑。
能不能不依赖后台「生成」按钮,直接用 PHP 命令行生成?
可以。织梦的 /plus/makehtml.php 和 /dede/makehtml_*_action.php 本质上都是几个 GetIDList + MakeArc 的循环。你完全可以写一个 cli_make.php 放在站点根目录下,include 完 common.inc.php 后调用同样的内部 API。这种纯 CLI 方案最大的好处是绕开了 PHP-FPM 的 max_execution_time、绕开了 Nginx 的 504 超时,跑大站点全量生成时稳得多。具体代码我之前在另一篇文章里贴过,这里不再展开。
写在最后
切表生成静态这套方案,本质上是用「数据库视角的临时配置切换」绕开了织梦只支持单套生成配置的限制。它不改源码、不破坏升级路径,只要你在每次操作前做好备份、严格按顺序跑SQL,基本不会出问题。
我自己写过一个Bash一键脚本,把上面五步全部串起来,带备份、带断点恢复、带钉钉报警。如果有读者感兴趣,可以在评论里说一声,抽时间整理成一个开源版本发出来。
另外补一句:如果你的站点已经稳定吃到了 PC 端搜索流量,但移动端 PV 一直起不来,先别急着升级模板或者重做小程序,把这套静态化做完往往就能看到立竿见影的收录变化——我个人维护的几个站,落地这套方案两到三周内移动端百度收录量都翻倍以上。
因本文不是用Markdown格式的编辑器书写的,转换的页面可能不符合AMP标准。