转: Apache SSI详解及应用

什么是 SSI?

SSI(Server Side Includes),是嵌套在 HTML 网页中的指示语句,由后台服务器进行代码的解释计算。使用 SSI 可以动态的创建一部分网页内容而不需要编写复杂的 JSP/ASP/PHP 等程序。SSI 是如此的小巧以至于不应算作一门语言,因为他远没有JSP/ASP/PHP 等程序那么复杂,只有一些极其有限的语法规则。

很多 HTTP Server 程序都支持 SSI,可能语法稍有不同,比如: IIS/Novell HTTP Server 等等,大同小异,本文要说明的是 Apache 2.0 的 SSI。闲话少说,我想告诉大家的是,这是一篇实践经验总结性的文章,后文中的示例解决方案都是来自实际的网站应用中。

开启SSI功能需先对apache配置文件(httpd.conf)进行设置 详情请百度

<Directory "D:/myProject/web">
AddType text/html .ssi    #这里可以是 .shtml 或其他 不一定要 .ssi, 设置.ssi后缀的也是text/html类型的文件
Options Includes
AddOutputFilterByType INCLUDES; DEFLATE text/html  #输出处理器
</Directory>

测试SSI是否成功启用 编辑文件

//  test.ssi :
# echo指令输出变量 DATE_LOCAL
<!--#echo var="DATE_LOCAL" -->
## 特别注意 <!--# 之间不能有任何空格,不然指令是无效的,被当作html注释

**因为很多IDE都有注释代码行的快捷键, 如 sublime text( ctrl + /) 但是会变成 <!-- #echo var="..." -->,由于多了个空格,所以ssi指令被当成注释了。 **

浏览器访问 http://localhost/test.ssi 能看到打印当前时间 说明SSI已启用


关于SSI的更多参考资料

这些文档也可以在 Apache的安装文件夹找到:
Apache Tutorial: Introduction to Server Side Includes
Apache mod_include

SSI语法:

<!--#fn attribute=value attribute=value ... --> fn可以理解成函数或者指令。 例子:

#环境变量习惯大写
http://<!--#echo var="SERVER_NAME" var="DOCUMENT_URI"-->  

#virtual的值可以是相对路径或绝对路径 如 virtual="/ssi/footer.ssi" 
<!--#include virtual="ssi/footer.ssi" --> 

#file的值只能是相对路径
<!--#include file="footer.ssi" --> 

#设置自定义变量
<!--#set var="protocol" value="http" --> 

SSI 语句是直接嵌套在 HTML 页面中的,可以放置在任意的位置。所以 SSI 语句前后采用 HTML 注释的写法,这样一旦服务器关闭了对 SSI 的支持,此时访问页面的话,也不会直接在网页上显示出不必要的代码。

SSI不区分大小写,环境变量用大写是很好的习惯;
SSI中只有一种数据类型:字符串;
SSI中的转义符是 \ ,字符串可以用双引号或单引号包裹 ,同JS

SSI 中的变量分为自定义变量和环境变量**

自定义变量使用 set 命令来创建:<!--#set var="protocol" value="http" -->
环境变量是系统已经存在的一些默认的变量和变量值,可以直接使用。 <!--#echo var=”DATE_LOCAL” -->
DATE_LOCAL 就是一个环境变量,用来显示当前本地时间。类似的环境变量还有很多,比如常用HTTP_HOST、SERVER_NAME、DOCUMENT_URI、DOCUMENT_NAME 等等。

# 查看所有环境变量
# 由于无换行所以按ctrl+u,以网页源代码的方式查看更清晰点
<!--#printenv--> 

# ------- 应用示例: --------------
<body>
    <!--#include virtual="/bnn/ssi/header.ssi"-->
    <div id="Main">
        <div id="Content">
            <p>This is "<a href="http://<!--#echo var=\'SERVER_NAME\' -->">Learning Apache SSI</a>" testing page!</p>
            <p>Hello SSI</p>
            <p>Today is: <!--#echo var="DATE_LOCAL" --></p>
        </div>
    </div>
    <!--#include virtual="ssi/footer.ssi"-->
    </body>

数据类型:SSI 中只有一种数据类型“字符串”。例如:

<!--#set var=”MyFirstVar” value=”120” -->
<!--#set var=”MySecondVar” value=”20” -->
# $MyFirstVar < $MySecondVar  //因为2个变量都是字符串值 所以执行的是字符串比较(比较每个字符的ASCII码大小)

SSI常用指令

SSI 的元素并不多,下面列出常用的元素和属性,其它请查看官方参考。

echo :将变量值写入 HTML 代码中。

#可以一次输出多个变量值 
<!--#echo var="DATE_LOCAL"--> 
http://<!--#echo var=”SERVER_NAME” var=”DOCUMENT_URI” -->

include :在语句所在位置引入子页面。

include 是 SSI 中最常用的命令,也是 SSI 主要功能的体现。

# virtual的值可以是相对路径或绝对路径, 但注意路径中不能包含主机名;
#路径可以是相对当前文件(SSI 语句所在的页面)或者从“/”开始,相对网站根目录的路径;
<!--#include virtual="ssi/header.ssi"--> 
# 路径后允许加参数
<!--#include virtual="/cgi-bin/ap/optin_cn.pl?btn=send&fax=yes" --> 

SSI 是允许嵌套的;例如,假设有三个文件,file1 include file2,file2中 include file3。

set :创建变量或修改变量值

<!--#set var=”Protocol” value=”http” -->
# 若变量值带引号,可以这样:
<!--#set var="MyVar1" value=\'"IBM"\' -->  //value的值可以是字符串常量或者变量 如:value="$MyVar2" 
<!--#set var="MyVar2" value="\"IBM\"" -->

SSI中的变量都带$前缀 如:$Myvar,为了更清晰的表达一个变量 通常用大括号把变量名包起来 ${MyVar} , 同php

<!--#set var="MyVar1" value="IBM" -->
<!--#set var="MyVar2" value="Services" -->
<!--#set var="MyVar3" value="${MyVar1}${MyVar2}" -->  //设置 MyVar3 = MyVar1+MyVar2
<!--#echo var="MyVar3" -->

<!--#set var="MyVar3" value="abc${MyVar1}_${MyVar1}def" --> // 修改MyVar3的值
<!--#echo var="MyVar3" -->

<!--#set var=”MyVar1” value=”IBM” -->
<!--#set var=”MyVar2” value=”\$MyVar1” --> // 变量值为 "$IBM"

# 另一个把变量写在 SSI 语句中的例子:
<!--#include virtual="/servers/eserver/${cc}/ssi/nav_left.ssi" -->  // 这个比较有用。

fsize 和flastmod

显示指定文件的大小(fsize)和指定文件的最后修改时间(flastmod)

virtual – 与元素 include 中的属性相同,<!--#fsize virtual=”/cgi-bin/cmail.pl” --> 结果返回的是这个 Perl 脚本文件的大小,而不是运行这段 Perl 脚本的结果。

SSI 配置元素

  • config指令
    配置一些 SSI 运行结果;错误信息、文件大小格式、时间格式。
    errmsg属性 当 SSI 语句运行出错时显示的信息。 例如:<!--#config errmsg="出错啦# " -->
    sizefmt 显示以何种方式显示文件大小。这个属性有两个值:bytes 和 abbrev。

      <!--#config sizefmt="bytes" -->  //按bytes大小显示
      <!--#config sizefmt="abbrev" --> //按bytes、Kb或Mb动态显示 视文件大小
    

    timefmt 显示时间的格式。属性值的参数同 C 标准库中的strftime(3) 相同;

      <!--#config timefmt="%Y-%m-%d"-->
      <!--#config timefmt="%Y-%m-%d"-->
      <meta name="DC.DATE" scheme="iso8610" content="<!--#echo var=’LAST_MODIFIED’-->">
    

流控制元素

条件语句

SSI 中只有条件语句一种结构,而且结构很简单。基本的控制元素:

<!--#if expr="test_condition"-->
    html or SSI statements
<!--#elif expr="test_condition"-->
    html or SSI statements
<!--#else-->
    html or SSI statements
<!--#endif-->
## if 语句可以嵌套,你可以在 if 块中再加入一个 if 块语句。

非空字符串为真,空串为假

<!--#if expr="IBM" -->  // 表示条件成立;
<!--#if expr="" -->  //空字符,返回 假,条件不成立。

判断一个变量是否为空字符串的一种写法:<!--#if expr="$MyVar = ‘’" -->

比较运算符 = != < <= > >=

<!--#if expr="$DOCUMENT_URI = ‘/bnn/index.html’" -->
codes
<!--#endif -->

逻辑运算符 ! && || 同JS

运算符优先级 比较运算符优先级高于逻辑运算符 ; && 和 || 具有相同的优先级,可以使用括号 () 进行分组。

<!--#if expr="$a = test1 && $b = test2" -->
<!--#if expr="($a = test1) && ($b = test2)" -->

任何不被识别为变量或者操作符都被当作是一个字符串。字符串也可以使用引号(单引号或者双引号)括起来。不被引号括起来的字符串中不允许有空格或者 Tab,因为空格是被用来起到分隔的作用。如果一个字符串中包含空格,请使用引号括起来。

<!--#if expr="$a = test1 && $b = ‘test 2’" -->

正则表达式

Regular expression (正则表达式,缩写 RE),是一种对字符串进行匹配查找的高效模式。几乎每一种语言都支持 RE;Apache SSI 中的 RE 语法同 Perl(版本 5)语言中的相同,但并不完整的支持

<!--#if expr="$QUERY_STRING = /^sid=([a-zA-Z0-9]+)/" -->
    <!--#set var="session" value="$1" -->
<!--#endif -->

说明:此例表示从参数中提取子字符串。$QUERY_STRING 是环境变量,表示通过网页 URL 传递过来的参数,例如:
http://www.IBM.com/index.html?sid=safsaf43513sadfz&cntry=cn 其中,问号后面的部分就是 $QUERY_STRING 的值。

如果等号右边的比较部分是 / / 这种形式,则表示,这部分是正则表达式

/^sid=([a-zA-Z0-9]+)/ 括号表示分组,用圆括号分组的同时,程序自动会将圆括号内匹配的部分提取出来保存在 $1 这个变量中;这个 $1 是系统变量,用来保存正则表达式分组提取出来的各个部分值,一共有 9个,$1-$9。

SSI 与 JavaScript

SSI 与 JS 如何一起使用呢?是这样的,由于服务器并不能识别 JS 代码,所以可以把 SSI 语句放到 JS 代码行中,这样取代一部分 JS 代码的工作,将这部分工作放到服务器端运行。

<!--#if expr="$DOCUMENT_URI = /\/bnn\//" -->  //正则匹配 形如:/bnn/ 的路径,然后设置变量 SSI变量在JS中输出
    <!--#set var="LASLink" value="http://localhost/bnn/" -->
    <!--#set var="LASText" value="Learning Apache SSI" -->
<!--#endif -->

<script type="text/javascript">
//<![CDATA[
    document.write(‘<a class="fbox" href="<!--#echo var="LASLink" -->"><!--#echo var="LASText" --></a>’);
//]]>
</script>

SSI 与 日期

前几天遇到这样一个需求:一个 Promotion – 3月3日之前显示默认的内容,3月3日之后显示另外一个内容。下面给出这段代码,分享一下类似这种的要求该如何入手。

<!--#config timefmt="%Y-%m-%d"--> # 配置日期格式
<!--#if expr="$DATE_LOCAL = /(.+)-(.+)-(.+)/" --> # 流程控制语句实现逻辑 正则匹配当前本地日期 捕获年月日
    <!--#if expr="($2 = \'03\') && ($3 != /0[1-3]/)" --> # 嵌套的if 正则跟字符串比较?
        3月3日之后
    <!--#else -->
        默认
    <!--#endif -->
<!--#endif -->

SSI与页面布局

页面布局中一些相对固定的模块,可以通过include的方式包含到页面中。
通常情况下,上面有 4个区域是不经常变动的:Header、Left Nav、Nav Trail 和 Footer。

<body>
<!--#include virtual="ssi/header.ssi"--> # 把头部模块包含进来
    <div id="Main">
        <div id="LeftNav"><!--#include virtual="ssi/nav_left.ssi"--></div> # 左侧导航模块包含进来
        <div id="RightNav"><!--#include virtual="ssi/nav_right.ssi"--></div> # ~右侧导航模块include进来
        <div id="Content">
            <div id="NavTrail"><!--#include virtual="ssi/nav_trail.ssi"--></div> # 面包屑模块include进来
        <p>Hello SSI</p>
        </div>
    </div>
    <!--#include virtual="ssi/footer.ssi"--> # 页脚模块include进来
</body>


<!--#set var="protocol" value="" --> # 设置变量protocol初始值 
<!--#if expr="$HTTPS != /ON/" --> # 若环境变量$HTTPS 开启,则设置变量protocol的值
    <!--#set var="protocol" value="http://${SERVER_NAME}" -->
<!--#endif -->
<!--#set var="protocols" value="https://${SERVER_NAME}" --> # 设置变量 变量名比较长的话用大括号包起来比较清晰,易于解析。

# 根据请求的路径 高亮显示相应的栏目链接
<ul>
    <li class="TopLink">
        <a class="left-nav-overview" href="<!--#echo var=\'protocol\' -->/ ">IBM</a>
    </li>
    <li class="PrimaryLink<!--#if expr=\'$DOCUMENT_URI = /\/systems\/cn\//\' -->-Highlight<!--#endif -->">
        <a class="left-nav" href="<!--#echo var=\'protocol\' -->/systems/cn/">Systems</a>
    </li>
    <li class="PrimaryLink<!--#if expr=\'$DOCUMENT_URI = /\/contact\/index.html/\' -->-Highlight<!--#endif -->">
        <a class="left-nav" href="<!--#echo var=\'protocols\' -->/contact/index.html">联系我们</a>
    </li>
</ul>

Nav Trail 又叫做 Breadcrumb,中文里我们叫做“当前位置”。在页面上,根据当前页面所在不同,在这个地方会有提示访问者当前所在的位置。如果在每个页面都存在这个提示的话,编辑起来会很麻烦。但现在可以使用 SSI 解决这个问题,只要在每个页面的这个位置 include 一个 SSI 文件就可以了,当前所在位置的工作交给 SSI 来完成。

<!--#set var="protocol" value="" --> # 设置变量protocol初始值
<!--#if expr="$HTTPS != /ON/" --> # 若url是 https:// 安全访问模式
    <!--#set var="protocol" value="http://${SERVER_NAME}" --> # 设置变量 protocol的值
<!--#endif -->
<!--#set var="protocols" value="https://${SERVER_NAME}" --> 

# 设置一系列变量值 当前位置的链接和文本
<!--#set var="NavTrailLink1" value="" -->
<!--#set var="NavTrailLinkName1" value="" -->

<!--#set var="NavTrailLink2" value="" -->
<!--#set var="NavTrailLinkName2" value="" -->

<!--#set var="NavTrailLink3" value="" -->
<!--#set var="NavTrailLinkName3" value="" -->

#  设置值时是多重if嵌套
<!--#if expr="$DOCUMENT_URI = /\/bnn\// && $DOCUMENT_URI != /\/bnn\/index.html/" --> # 若是访问/bnn/下非index.html页面
    <!--#set var="NavTrailLink1" value="${protocol}/bnn/" --> # 设置一级文本和链接变量值
    <!--#set var="NavTrailLinkName1" value="BNN" -->

    <!--#if expr="$DOCUMENT_URI = /\/bnn\/books\// && $DOCUMENT_URI != /\/bnn\/books\/index.html/" --> # 若是访问/bnn/books/下非index.html页面
        <!--#set var="NavTrailLink2" value="${protocol}/bnn/books/" --> # 设置二级文本和链接变量值 如此类推
        <!--#set var="NavTrailLinkName2" value="图书馆" -->

    <!--#elif expr="$DOCUMENT_URI = /\/bnn\/food\// && $DOCUMENT_URI != /\/bnn\/food\/index.html/" -->
        <!--#set var="NavTrailLink2" value="${protocol}/bnn/food/" -->
        <!--#set var="NavTrailLinkName2" value="好吃的" -->

        <!--#if expr="$DOCUMENT_URI = /\/bnn\/food\/strawberry\// && $DOCUMENT_URI != /\/bnn\/food\/strawberry\/index.html/" -->
            <!--#set var="NavTrailLink3" value="${protocol}/bnn/food/strawberry/" -->
            <!--#set var="NavTrailLinkName3" value="草莓" -->
        <!--#endif -->

    <!--#endif -->
<!--#endif -->

# 输出当前位置时也是多重if嵌套
<img alt="" class="display-img" height="6" src="//www.ibm.com/i/c.gif" width="1" />
<!--#if expr="$NavTrailLink1" -->
    <a class="bctl" href="<!--#echo var=\'NavTrailLink1\' -->"><!--#echo var="NavTrailLinkName1" --></a><span class="bct">&nbsp;&gt;&nbsp;</span>
    <!--#if expr="$NavTrailLink2" -->
        <a class="bctl" href="<!--#echo var=\'NavTrailLink2\' -->"><!--#echo var="NavTrailLinkName2" --></a><span class="bct">&nbsp;&gt;&nbsp;</span>
        <!--#if expr="$NavTrailLink3" -->
            <a class="bctl" href="<!--#echo var=\'NavTrailLink3\' -->"><!--#echo var="NavTrailLinkName3" --></a><span class="bct">&nbsp;&gt;&nbsp;</span>
        <!--#endif -->
    <!--#endif -->
<!--#endif -->

SSI指令小结

语法: <!--#directive [parm=value] --> ,指令包括:

  • config:设置日期格式等,如:(<!--#config timefmt="%B %Y" -->)
  • echo:打印变量值 (<!--#echo var="VARIABLE_NAEM" -->)
  • exec:用来执行服务器端的命令
  • include:文件包含 (<!--#include virtual="file-name" -->)
  • flastmod:输出指定文件最后修改时间(<!--#flastmod file="filename.shtml" -->)
  • fsize:输出指定文件的大小(<!--#fzie file="filename.shtml" -->)
  • printenv:打印所有环境变量(<!--#printenv -->)
  • set:设置或修改变量 (<!--#set var="foo" value="Bar" -->)
  • if elif endif else:创建条件分支

版权声明:本文为stephenykk原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/stephenykk/p/5393890.html