mod_include(ssi)仅支持静态内容拼接与极简条件判断,不支持变量运算、循环或外部数据读取;需启用模块、配置options +includes及addtype等才能生效,且变量来源受限、路径受安全约束。

mod_include(SSI)不能实现真正意义上的“服务器端逻辑”,它只支持极简的条件判断和静态内容拼接,不支持变量运算、循环、函数调用或外部数据读取。它的作用是让 HTML 页面在被发送给浏览器前,由 Apache 做一次轻量文本替换——比如根据 URL 参数显示不同段落,或复用页眉页脚。想用它做复杂逻辑,会很快撞墙。
必须先启用模块并配置解析权限
即使写对了 <!--#if -->,页面仍原样输出或报 500 错误,大概率是基础配置没到位:
- 确认模块已加载:
a2enmod include(Debian/Ubuntu),或检查httpd.conf中LoadModule include_module modules/mod_include.so未被注释 - 允许目录执行 SSI:
Options +Includes(常放在<directory></directory>或虚拟主机配置中),不能只写IncludesNOEXEC就以为够了——IncludesNOEXEC是权限选项,不是开启开关 - 指定哪些后缀触发解析:默认只处理
.shtml,若要用.html,需加两行:AddType text/html .htmlAddOutputFilter INCLUDES .html - 重启 Apache 生效:
systemctl restart apache2或apachectl restart
条件判断只能基于有限变量和简单表达式
SSI 的 #if 不是编程语言里的 if,它只支持字符串匹配、正则(有限)、环境变量比对,且变量来源非常受限:
- 可用变量极少:默认暴露
DOCUMENT_URI、QUERY_STRING、HTTP_HOST、DATE_LOCAL等,HTTP_USER_AGENT这类请求头默认不可见,不能直接用$HTTP_USER_AGENT - 语法严格:
<!--#if expr="$QUERY_STRING = /page=about/" -->中的正则需用斜杠包围;等号前后不能有空格;引号必须是英文双引号 - 不支持嵌套或复合条件:
expr="$a = 'x' && $b = 'y'"会失败;!$var也不被识别 - 示例可行写法:
<!--#if expr="($QUERY_STRING = /page=contact/) || ($QUERY_STRING = /page=about/)" --><br> <p>这是联系或关于页</p><div class="aritcle_card flexRow artxards"> <div class="artcardd flexRow"> <a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill3961" title="Apache Superset Dashboard and SQL Exploration Skill"><img src="https://img.php.cn/upload/skill/000/000/081/178987691575372.jpg" alt="Apache Superset Dashboard and SQL Exploration Skill" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a rel="nofollow" href="/xiazai/skill3961" title="Apache Superset Dashboard and SQL Exploration Skill" class="overflowclass">Apache Superset Dashboard and SQL Exploration Skill</a> <p class="overflowclass">Apache Superset 是一个广泛采用的开源 BI 平台,用于 SQL 探索、图表构建和仪表板交付。当代理需要查询仓库数据、组装仪表板或使用成熟的分析界面解释指标而不是临时笔记本代码时,此技能非常有用。</p> </div> <a rel="nofollow" href="/xiazai/skill3961" title="Apache Superset Dashboard and SQL Exploration Skill" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div><br><!--#else --><br> <p>默认首页内容</p><br><!--#endif -->
文件包含分 virtual 和 file,路径规则完全不同
用错路径参数是 SSI 失败最常见原因,两者行为差异大,不能混用:
-
file指令走文件系统路径:<!--#include file="nav.html" -->中的nav.html必须和当前文件在同一目录;../header.html会被拒绝(出于安全限制) -
virtual指令走 URL 路径:<!--#include virtual="/inc/footer.shtml" -->中的路径以网站根目录(DocumentRoot)为起点,可跨目录,但目标文件也必须能被 Web 访问(即不能是/etc/passwd) - 被包含文件默认不递归解析 SSI —— 即使它内部也有
<!--#include -->,也不会执行。如需嵌套,被包含文件本身也得是.shtml后缀,并确保其所在目录同样配置了Options +Includes - 注意权限:SELinux 或文件系统权限禁止 Apache 读取目标文件时,会静默失败或返回错误提示(取决于
config errmsg设置)
调试技巧:让错误可见,而不是静默吞掉
默认情况下,SSI 解析失败不会报错,而是直接跳过指令,导致页面“少一块”却找不到原因:
- 在页面顶部加这行,让错误显形:
<!--#config errmsg="[SSI ERROR: %s]" -->,失败时会显示具体提示 - 测试变量是否可读:
<!--#echo var="QUERY_STRING" -->,如果为空,说明请求没带参数,或 Apache 没传该变量 - 检查响应头:用浏览器开发者工具看返回的
Content-Type是否为text/html;如果是text/plain,说明AddType没配对 - 日志定位:
tail -f /var/log/apache2/error.log,SSI 报错通常出现在这里,比如 “unable to include …” 或 “no such file or directory”










