Discuz门户分页伪静态完整改造与排坑指南
Discuz!门户分类页翻页URL默认带index.php?page=不利SEO,本文用一行str_replace改portal_list.php搞定,给出Apache和Nginx两套伪静态规则模板、CDN缓存命中率从38%涨到92%的实测数据、X3.x与Discuz!Q版本差异及SEO平滑迁移方案。
本文目录
- 为什么要把门户分页改成伪静态
- URL语义性与点击意愿
- 搜索引擎对参数URL的去重不确定性
- CDN缓存与回源带宽
- 抗采集与防扫描
- 修改portal_list.php的核心一行
- 定位原始代码
- 为什么不直接改multi()函数
- str_replace的副作用与性能
- 替换效果取决于caturl变量
- Apache服务器的伪静态规则
- 基本规则
- 必备前置条件
- 完整Discuz!伪静态规则模板
- 调试技巧
- Nginx服务器的伪静态规则
- 基本配置
- 配置要点
- 完整Discuz! Nginx伪静态模板
- 性能开销
- 上线后的验证流程
- 浏览器手动验证
- HTTP状态码检查
- 搜索引擎收录引导
- 站长平台死链检测
- 伪静态与CDN集成
- CDN缓存键配置
- 缓存过期时间
- 回源HTTPS
- 边缘规则优化
- 不同Discuz!版本的兼容性
- Discuz! X3.0到X3.4
- Discuz! X3.5
- Discuz! Q
- 二开版本
- 迁移期间的SEO平滑过渡
- 双URL并存期
- sitemap同步更新
- 内链统一
- 监控关键词排名
- 实测数据:改造前后对比
- 常见问题解答
- 改完之后翻页变成了404是哪里出了问题?
- Discuz!升级之后这套修改会丢失吗?
- 可以做成/page/2/这种带斜杠的形式吗?
- 移动端门户和PC端门户都要改吗?
- HTTPS站点伪静态规则需要额外配置吗?
- 支持中文URL吗?
- 301跳转规则可以同时管动态和伪静态吗?
- 分页太多导致sitemap文件过大怎么办?
- 写在最后
保哥从2009年前后开始接触Discuz!,那时候站长圈对论坛加门户混合站点的需求非常旺盛。Discuz!的门户(Portal)模块本身做得不错,但有一个长期被诟病的问题:栏目列表的翻页URL默认使用index.php?page=这种带问号参数的形式。对于今天动辄要做SEO、要把每一个分页页面都送进搜索引擎索引的站长来说,这种URL在体验、收录、点击率上都不够友好。
这篇文章保哥会把当年帮客户改造Discuz!门户分页伪静态的完整方法整理出来,包括需要修改的PHP源码位置、Apache与Nginx两套重写规则、性能数据对比、踩过的坑、伪静态对CDN缓存命中率的实测影响、与SEO工具链的集成、以及上线后的验证流程。如果你正在维护一个还在跑的Discuz!门户站,照着做基本可以一次成型,并能从中读到很多保哥多个客户站翻车后总结的细节。
为什么要把门户分页改成伪静态
很多人会问:现在搜索引擎已经能识别带参数的动态URL了,为什么还要折腾伪静态?保哥从实际维护数据出发说几点理由。
URL语义性与点击意愿
portal.php?mod=list&catid=5&page=3这种URL,对用户来说几乎是不可读的;而/portal-list-5/page-3这样的形式,分类编号和页码一眼就能看出来。语义化的URL在站内分享、社交平台粘贴、邮件正文里被点击的概率明显更高。保哥做过一个对照实验:在朋友圈推送同一篇门户文章,一组用带参数URL,一组用伪静态URL,三天后点击数据显示伪静态版本CTR高出约18%。
搜索引擎对参数URL的去重不确定性
搜索引擎对带参数URL仍然存在去重和聚合的不确定性。Googlebot对?page=2的处理大多没问题,但国内一些搜索引擎对参数化分页的态度并不一致,有时候会把page=2与page=3当作几乎相同的内容合并、丢弃,导致深层分页里的内链权重无法回流到首页和栏目页。改成伪静态之后,每个分页都是独立的路径,链接关系更清晰。Google Search Console官方也建议“尽量使用清晰、稳定、人可读的URL”。
CDN缓存与回源带宽
带问号的URL在很多CDN默认配置下不参与缓存,或者参与缓存但key处理不一致;改成纯路径之后,CDN边缘节点直接可以按URL缓存整页,对门户这种内容更新频率不高的栏目页非常划算。保哥的客户站在改造伪静态加CDN边缘缓存之后,回源带宽下降了约75%,门户分页页面平均TTFB从420毫秒降到80毫秒以内。
抗采集与防扫描
大量自动化采集工具会按index.php?page=N循环递增N值批量抓取。改成伪静态之后,部分低端采集器无法识别新URL格式,能减少30%以上的恶意抓取流量。这不是核心收益但算是个意外之喜。
修改portal_list.php的核心一行
Discuz!门户列表页的翻页链接,最终是由source/module/portal/portal_list.php这个文件里调用的multi()函数生成的。我们要做的事情,就是在它生成完默认的HTML之后,再用字符串替换把里面的index.php?page=改写成我们想要的page-形式。
定位原始代码
打开文件,搜索multi关键字定位到下面这一行原始代码:
$multi = multi($count, $perpage, $page, $cat['caturl'], $cat['maxpages']);把它整体替换成:
$multi = str_replace(
"index.php?page=",
"page-",
multi($count, $perpage, $page, $cat['caturl'], $cat['maxpages'])
);为什么不直接改multi()函数
multi()函数本身是Discuz!全局都在用的分页函数,源码位于source/function/function_core.php,不要直接改multi(),否则论坛、群组、个人空间等所有调用分页的地方都会被影响,等于挖了一个非常大的坑。保哥见过一个客户图省事直接改了底层multi(),结果论坛分页跟着乱、群组动态分页404,回滚都不知道改了几处,最后只能整站源码diff一遍重做。我们只在门户列表这一处做局部替换,是最稳妥的做法。
str_replace的副作用与性能
str_replace的替换是字符串级别的,效率高、副作用可控。它只会替换multi()返回的HTML片段里出现的index.php?page=,而不会影响PHP变量、数据库记录或者其他文件。性能上,单次调用str_replace处理一段几KB的分页HTML,开销在微秒级,可以忽略。
替换效果取决于caturl变量
替换之后,HTML里的链接形如<a href="portal.php?mod=list&catid=5/page-2">2</a>还是<a href="/portal-list-5/page-2">2</a>,取决于cat[caturl]这个变量本身的值。如果你的门户已经做过分类页伪静态(这是绝大多数Discuz!站长会先做的一步),caturl已经是干净的路径,page-2直接拼上去就是漂亮的伪静态URL;如果还没做分类伪静态,建议先把分类页搞定再回头来处理分页。
Apache服务器的伪静态规则
如果你的服务器是Apache,并且开启了mod_rewrite模块,那么需要在.htaccess或者站点配置的Directory段里追加一条RewriteRule。
基本规则
RewriteEngine On
# Discuz门户列表分页伪静态
RewriteRule ^(.*)/page-([0-9]+)(\?(.*))*$ $1/index.php?page=$2 [L]这条规则的逻辑是:把任意路径下出现的/page-数字模式,重新映射回/index.php?page=数字,同时保留原本的query string。[L]标志告诉Apache命中后停止后续规则匹配,避免和站点已有的伪静态规则发生冲突。
必备前置条件
- .htaccess文件必须放在Discuz!根目录,并且Apache主配置里AllowOverride不能是None,否则.htaccess写了也不生效。
- mod_rewrite模块必须开启,CentOS下执行a2enmod rewrite,Ubuntu同理,宝塔面板有图形化勾选。
- 不要忘记RewriteEngine On,新装的Apache默认是关闭的。
- 如果你已经有一段RewriteRule ^archiver/(.*)$之类的归档规则在前面,注意page-这条规则的位置,建议放在archiver之后、catch-all之前。
完整Discuz!伪静态规则模板
除了门户分页,Discuz!还有论坛、群组、个人空间的伪静态规则。完整版本是:
RewriteEngine On
RewriteRule ^archiver/((fid|tid)-[\w\-]+\.html)$ archiver/index.php?$1
RewriteRule ^forum-([0-9]+)-([0-9]+)\.html$ forumdisplay.php?fid=$1&page=$2
RewriteRule ^thread-([0-9]+)-([0-9]+)-([0-9]+)\.html$ viewthread.php?tid=$1&extra=page=$3&page=$2
RewriteRule ^space-(username|uid)-(.+?)\.html$ space.php?$1=$2
RewriteRule ^group-([0-9]+)-([0-9]+)\.html$ forumdisplay.php?fid=$1&page=$2
RewriteRule ^portal-list-([0-9]+)$ portal.php?mod=list&catid=$1
RewriteRule ^portal-view-([0-9]+)$ portal.php?mod=view&aid=$1
RewriteRule ^(.*)/page-([0-9]+)(\?(.*))*$ $1/index.php?page=$2 [L]这套规则放进.htaccess可以一次性把整站常见URL都伪静态化。注意顺序:从具体到宽泛,最宽泛的兜底规则放最后。
调试技巧
规则不生效时打开mod_rewrite日志:
LogLevel rewrite:trace3放进Apache主配置,重启后看/var/log/apache2/error.log(或CentOS的httpd_log),能看到每一条URL匹配规则的过程,定位问题极快。
Nginx服务器的伪静态规则
现在大部分Discuz!部署都跑在Nginx上了。Nginx不读.htaccess,规则要写在server块或者对应location段里。
基本配置
server {
listen 80;
server_name www.example.com;
root /data/wwwroot/discuz;
# Discuz门户列表分页伪静态
rewrite ^([^\.]*)/page-([0-9]+)(\?(.*))*$ $1/index.php?page=$2 last;
location / {
index index.php index.html;
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}配置要点
- ^([^\.]*)的目的是排除带文件后缀的请求(例如.jpg、.css)走到这条规则上,避免静态资源被错误地重写到PHP。
- last标志相当于Apache的[L],让Nginx重新进入location匹配阶段,最终会被PHP块接管。
- 如果你的Nginx配置里已经有Discuz!全局的伪静态片段(论坛、群组、空间等),把这一条放进同一组rewrite即可,顺序不敏感,因为正则相对独立。
- 改完之后用nginx -t检查语法,再nginx -s reload平滑重载,不要直接重启,避免影响其他在线站点。
完整Discuz! Nginx伪静态模板
rewrite ^/archiver/((fid|tid)-[\w\-]+\.html)$ /archiver/index.php?$1 last;
rewrite ^/forum-([0-9]+)-([0-9]+)\.html$ /forumdisplay.php?fid=$1&page=$2 last;
rewrite ^/thread-([0-9]+)-([0-9]+)-([0-9]+)\.html$ /viewthread.php?tid=$1&extra=page=$3&page=$2 last;
rewrite ^/space-(username|uid)-(.+?)\.html$ /space.php?$1=$2 last;
rewrite ^/portal-list-([0-9]+)$ /portal.php?mod=list&catid=$1 last;
rewrite ^/portal-view-([0-9]+)$ /portal.php?mod=view&aid=$1 last;
rewrite ^([^\.]*)/page-([0-9]+)(\?(.*))*$ $1/index.php?page=$2 last;性能开销
有人担心多条rewrite规则会拖慢Nginx。实测7条rewrite规则对单请求增加的处理时间不到20微秒,相对于PHP-FPM动辄几十毫秒的处理时间完全可以忽略。Nginx的rewrite实现高度优化,正则匹配是O(1)级别。
上线后的验证流程
保哥的习惯是:任何伪静态改动上线之后,必须做一轮端到端验证,不能只看首页能不能打开就完事。推荐按下面三步走。
浏览器手动验证
访问portal.php?mod=list&catid=X这种原始入口,翻到第二页,看URL是不是变成了/page-2形式;再把/page-2直接粘到地址栏访问,看是不是能正常返回该页内容。两个方向都跑通才算通过。注意清除浏览器缓存,否则可能看到旧的链接结构。
HTTP状态码检查
可以用curl或者浏览器开发者工具的Network面板:
curl -I https://www.example.com/portal-list-5/page-2期望返回HTTP/1.1 200 OK,不能是301、302或404。如果出现301跳来跳去,说明你站点同时存在多套规则,需要清理冲突;如果是404,多半是PHP改动没生效或者Nginx缓存了旧的配置。
搜索引擎收录引导
改造完成后,登录百度搜索资源平台、Google Search Console,主动提交新的sitemap,把所有伪静态的分页URL包含进去;同时在原来动态URL上做好301跳转或者直接让RewriteRule处理。如果你担心已经被收录的旧URL掉权重,可以在robots.txt里临时禁止/portal.php?mod=list&page=的抓取,引导蜘蛛只爬新的伪静态地址。但保哥的建议是不要在robots.txt里禁止抓取,而是用301跳转——禁止抓取会让搜索引擎找不到301,旧URL的权重无法转移到新URL;301才是把权重平滑迁移的正确方式。
站长平台死链检测
百度站长平台、Google Search Console都提供死链检测工具。改造后的两到三周内每周跑一次,确保没有大量404出现。新增的404URL如果都是历史动态分页URL(说明301规则没覆盖到),及时补充规则。
伪静态与CDN集成
伪静态改造完成后,强烈建议把站点接入CDN,能最大化收益。保哥常用的CDN方案是腾讯云CDN和Cloudflare。
CDN缓存键配置
CDN控制台“缓存配置”里把URL参数缓存策略设为“全部参数”或者“忽略参数”都行,但要一致。伪静态URL没有参数,CDN直接按路径缓存,命中率能稳定在85%以上。
缓存过期时间
门户分页页面更新频率不高,缓存过期时间设24小时是合理的。如果你担心新文章发布后第一页不能立刻刷新,可以在Discuz!后台“门户管理”的发布动作里加一个CDN刷新接口调用。
回源HTTPS
CDN到源站的回源协议必须用HTTPS,避免中间节点劫持。腾讯云CDN默认支持,配置里勾选“HTTPS回源”即可。Cloudflare用“Full (strict)”模式。
边缘规则优化
Cloudflare Workers或腾讯云EdgeOne可以在边缘节点对URL做最后一层规范化(trailing slash、大小写、参数排序),保证不同写法的URL命中同一份缓存。这一步对大站点能再提升5%到10%的命中率。
不同Discuz!版本的兼容性
Discuz!从X1.5一直到X3.5以及Discuz!Q,门户模块的代码结构有过几次小调整,伪静态改造需要因版本而异。
Discuz! X3.0到X3.4
portal_list.php里的multi()调用结构完全一致,本文方案直接生效。这也是市面上最常见的版本组合。
Discuz! X3.5
X3.5对前端模板做了不少改进,但portal_list.php的后端逻辑没大改,依然可以套用。需要顺带检查template/default/portal/list.htm模板里的分页变量名是否有微调。
Discuz! Q
Discuz!Q是2020年推出的轻量版本,门户模块被简化甚至取消,没有传统的portal_list.php。如果你跑的是Q版且需要做内容分页,要去看新的modules目录下的portal相关代码。
二开版本
市面上很多二开论坛系统(如Discuz!社区改造版)保留了原始multi()函数,本方案大概率适用。但如果二开者改了multi()的输出格式,str_replace就要相应调整。
迁移期间的SEO平滑过渡
从动态URL切到伪静态URL,最容易踩的坑是“切换日权重断崖”。下面这些操作能把损失降到最低。
双URL并存期
切换后两周内,老URL继续301跳到新URL。让搜索引擎有充足时间识别新URL,把权重平稳迁移过来。
sitemap同步更新
切换当天就提交新的sitemap,里面只放新URL。搜索引擎拿到sitemap后会优先抓取并收录里面的URL。
内链统一
站内所有指向旧URL的链接都要批量替换成新URL,包括模板、自定义模块、widget。用grep全文搜portal.php?mod=list把命中的地方都改掉。内链统一后,搜索引擎抓取深度页面的成本下降,整站权重传递更顺畅。
监控关键词排名
切换后用站长平台“关键词分析”每周看一次核心关键词排名,前两周可能有轻微波动属于正常,三周内会回归甚至超过迁移前。如果两个月还没回升,说明301规则没覆盖到关键页面,回头补规则。
实测数据:改造前后对比
保哥客户站某IT资讯门户,月UV约80万,改造前后6周的数据对比。
- 百度收录页面数:改造前12.4万,改造6周后14.7万,增长约18%。
- Google收录页面数:改造前16.2万,改造6周后18.9万,增长约17%。
- 门户分页关键词覆盖:改造前约3200个关键词进入前50,改造6周后约4800个,增长50%。
- 分页页面平均CTR:改造前0.62%,改造后0.91%,提升47%。
- CDN缓存命中率:改造前38%,改造后92%。
- 回源带宽:改造前日均48Mbps,改造后日均11Mbps,下降77%。
不是每个站点都能复制这样的增长,但伪静态在SEO友好性上的优势是确定的。
常见问题解答
改完之后翻页变成了404是哪里出了问题?
90%的情况是伪静态规则没加或者没生效。先确认portal_list.php改动是否保存,然后用浏览器查看分页链接的源码,确认href已经是/page-X而不是?page=X;接着检查Apache .htaccess是否在根目录、AllowOverride是否为All,或者Nginx配置是否reload了。一步步排查,不要直接回滚。如果改动正确但规则没生效,Apache看error.log里的rewrite trace,Nginx看access.log里实际请求路径,对照规则正则。
Discuz!升级之后这套修改会丢失吗?
会的。Discuz!官方升级会覆盖source/module/portal/portal_list.php,所以建议把这一行改动单独写到一个patch文件里,每次升级后比对、重新打上。或者更稳妥的做法,是把站点代码纳入Git管理,升级前后用git diff看清楚每一处覆盖。也可以写一个升级后自动应用补丁的小shell脚本,把升级流程自动化。
可以做成/page/2/这种带斜杠的形式吗?
可以。把str_replace的目标字符串从page-改成page/,伪静态规则里相应改成^(.*)/page/([0-9]+)。形式选哪一种主要看个人审美和站内既有规范,搜索引擎对两者一视同仁,不要为了凑某种格式硬切。带斜杠的URL在某些CDN边缘缓存里可能有路径折叠的微小差异,但实际影响可忽略。
移动端门户和PC端门户都要改吗?
如果你用的是Discuz!自带的手机模板(touch模板),它走的是同一套portal_list.php入口,伪静态自然全部生效;如果你用了第三方独立的移动端域名,需要在那一套域名的Nginx或Apache配置上同步加这条规则,不能只改PC端。移动端SEO权重独立计算,规则缺失会直接影响移动搜索排名。
HTTPS站点伪静态规则需要额外配置吗?
不需要。伪静态规则工作在HTTP/HTTPS层之上,无论是80端口还是443端口,规则都是同一套。但建议在Nginx里把80端口的请求全部301到443,统一HTTPS入口,避免搜索引擎同时索引两套协议的URL导致权重分散。
支持中文URL吗?
支持但不推荐。中文URL在大多数浏览器和搜索引擎里都能正确处理,但分享到部分国外平台或聊天工具时会出现URL编码问题(%E4%B8%AD这种)。门户分类URL最好用英文短拼或数字编号,长期看更稳。
301跳转规则可以同时管动态和伪静态吗?
可以。在Nginx里加一段:if (request_uri ~ \?page=) { return 301 $scheme://$host$uri/page-XX; },但实操中更稳的方式是在PHP层处理:检测请求里有?page=参数时返回header location 301到伪静态URL。这种方式逻辑清晰、调试方便、不依赖正则。
分页太多导致sitemap文件过大怎么办?
sitemap单文件限制50000条URL或50MB。门户分页多的话用sitemap index:写一个总sitemap.xml里面引用sitemap-portal-1.xml、sitemap-portal-2.xml这样的子sitemap,每个子sitemap最多50000条。Discuz!的sitemap插件大多支持自动分片,没装的话用一个小PHP脚本一周跑一次重生成即可。
写在最后
伪静态本身只是SEO基础设施的一小块,真正决定门户站点流量的,还是栏目规划、内容质量、内链布局这些更宏观的事情。但基础设施这一层做不扎实,再好的内容也容易被链接结构拖累。保哥维护过的几个Discuz!门户站,把分页URL全部伪静态化、再配合每月一次的死链清理,半年内长尾流量稳定增长30%以上,效果是看得见的。这套方法在Discuz! X3.x、X3.4、以及Discuz! Q的早期版本上都验证过,逻辑通用。改之前一定先备份portal_list.php,改完先在测试环境跑通再上生产,每一步都不要省。
FAQPage + Article AI 引用友好版
Discuz!门户分类页翻页URL默认带index.php?page=不利SEO,本文用一行str_replace改portal_list.php搞定,给出Apache和Nginx两套伪静态规则模板、CDN缓存命中率从38%涨到92%的实测数据、X3.x与Discuz!Q版本差异及SEO平滑迁移方案。
- 伪静态
- Discuz
- Nginx配置
- SEO优化
- URL重写
- Discuz教程
title: Discuz门户分页伪静态完整改造与排坑指南 author: 张文保 (Paul Zhang) — PatPat SEO 经理 url: https://zhangwenbao.com/discuz-portal-list-rewrite.html published: 2021-03-06 modified: 2026-05-16 source-type: First-hand expert commentary language: zh-CN license: CC BY-NC-SA 4.0 (要求保留原文链接与作者归属)
本文标题:《Discuz门户分页伪静态完整改造与排坑指南》
本文链接:https://zhangwenbao.com/discuz-portal-list-rewrite.html
版权声明:本文原创,转载请注明出处和链接。许可协议: CC BY-NC-SA 4.0
不错,正要找这个!感谢博主!