标题:【Nginx36】Nginx学习:SSI静态文件服务器端包含模块

文章目录
    分类:存储运维 标签:Nginx

    Nginx学习:SSI静态文件服务器端包含模块

    这个模块让我想到了 2009 年刚刚工作的时候。最早我是做 .NET 的,而第一家公司其实是从 ASP 向 ASP.NET 转型中,因此,还是有不少的 ASP 做的页面。在那个时候,就用到了 SSI 。


    这么一说,大家估计也猜到了,这个功能其实是很早的技术了。现在的年轻大佬们可能很多都不知道这个功能。它可以让静态文件,也就是 HTML 文件实现一些简单的文件包含、定义变量、条件判断之类的功能。


    这个模块的名称是 ngx_http_ssi_module 模块,它是一个过滤器,用于处理通过它的响应中的 SSI(服务器端包含)命令。目前,支持的 SSI 命令列表不完整。


    SSI 模块的指令都可以在 http、server、location 下进行配置。SSI 模块是默认添加的模块,直接就可以使用。我们先来看看它的配置指令。这些配置不是今天的重点,今天的是重点是演示一下如何使用 SSI 。

    ssi

    启用或禁用响应中 SSI 命令的处理。

    ssi on | off;

    默认值是 off 。要使用 SSI 当然要把这个打开啦。

    ssi_last_modified

    允许在 SSI 处理期间保留原始响应中的“Last-Modified”标头字段,以促进响应缓存。

    ssi_last_modified on | off;

    默认值是 off 。默认情况下,当响应的内容在处理过程中被修改时,标头字段会被删除,并且可能包含动态生成的元素或部分,这些元素或部分会独立于原始响应而更改。

    ssi_min_file_chunk

    设置存储在磁盘上的响应部分的最小大小,从这里开始使用 sendfile 发送它们是有意义的。

    ssi_min_file_chunk size;

    默认值是 1k 。

    ssi_silent_errors

    如果启用,则在 SSI 处理期间发生错误时抑制“[an error occurred while processing the directive]”字符串的输出。

    ssi_silent_errors on | off;

    默认值是 off 。

    ssi_types

    除了“text/html”之外,还可以处理具有指定 MIME 类型的响应中的 SSI 命令。

    ssi_types mime-type ...;

    默认值是 text/html 。特殊值“*”匹配任何 MIME 类型 (0.8.29)。

    ssi_value_length

    设置 SSI 命令中参数值的最大长度。

    ssi_value_length length;

    默认值是 256 。

    变量

    • $date_local 本地时区的当前时间。格式由带有 timefmt 参数的 config 命令设置。

    • $date_gmt 格林威治标准时间的当前时间。格式由带有 timefmt 参数的 config 命令设置。

    SSI 语法

    对于上面配置指令和变量的内容咱们就不多说了,直接配置一个服务器来学习 SSI 的使用吧。

    server{
      listen 8036;
      root html;
    
      location /ssi/ {
        ssi on;
      }
      
      location ~ \.php$ {
        root html;
        fastcgi_pass unix:/var/sock/php-fpm/www.sock;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
      }
    }

    非常简单,就是监听了 8036 端口,然后定义了一个 /ssi/ 目录,然后再打开 ssi 功能。因为我们还会用到 PHP ,所以也加上了一个 PHP 的 FastCGI 配置。然后我们去 html 目录下创建一个 ssi 目录,在这个目录下面创建一个 index.html 文件。

    <!--# include file="header.html" -->
    <!--# include file="/ssi/header.php?title=testssi" -->
    
    <!--# set var="name" value="zyblog" -->
    <!--# set var="age" value="37" -->
    
    <!--# echo var="name" -->
    <!--# echo var="age" -->
    <!--# echo var="id" default="123456" -->
    
    
    <!--# if expr="$age = 37" -->
    37
    <!--# elif expr="$age != 40" -->
    young
    <!--# else -->
    old
    <!--# endif -->
    
    <!--# block name="one" -->
    this is block one.<br/>
    <!--# endblock -->
    <!--# include virtual="/ssi/abc.html" stub="one" -->
    <!--# include file="/ssi/123.html" stub="one" -->

    看出来这个 SSI 的语法了吧。

    <!--# command parameter1=value1 parameter2=value2 ... -->

    它直接使用 HTML 中的注释,但是在注释中添加了一个 # 符号作为开始符号。接着就是命令以及命令相关的参数 。上面代码中,我们使用 include 命令加载文件,使用 set 定义变量,使用 echo 输出变量。使用 if 命令进行逻辑判断,最后的 block 命令是定义一个块,如果 include 加载的文件不存在时,就使用一个 stub 参数指定一个 block 显示 block 里面的内容。


    接下来,准备最上面两个 include 需要加载的文件。

    <!-- header.html -->
    this is header.html!<br/>

    header.html 就是显示一句话。

    <?php
    // header.php
    $title = $_GET['title'];
    ?>
    title is '<?php echo $title;?>'!<br/>

    header.php 文件里面则是接收一个 title 参数 ,然后再把这个 title 参数打印出来。


    好了,咱们访问一下这个页面试下吧。

    ➜  ~ curl http://192.168.56.88:8036/ssi/
    this is header.html!<br/>
    
    
    
    title is 'testssi'!<br/>
    
    
    
    
    
    
    zyblog
    37
    123456
    
    
    
    37
    
    
    
    
    this is block one.<br/>
    
    
    this is block one.<br/>
    
    
    
    
    

    中间的空行我故意没有去掉,从这里可以看出,SSI 的命令行以及 PHP 代码在解析完成之后是会变成空行的。最下面的两个使用 block 的 include ,在错误日志文件中可以看到相应的错误信息。

    2022/09/21 23:20:28 [error] 1513#0: *38 open() "/usr/local/nginx/html/ssi/abc.html" failed (2: No such file or directory), client: 192.168.56.1, server: , request: "GET /ssi/index.html HTTP/1.1", subrequest: "/ssi/abc.html", host: "192.168.56.88:8036", referrer: "http://xxx"
    2022/09/21 23:20:28 [error] 1513#0: *38 open() "/usr/local/nginx/html/ssi/123.html" failed (2: No such file or directory), client: 192.168.56.1, server: , request: "GET /ssi/index.html HTTP/1.1", subrequest: "/ssi/123.html", host: "192.168.56.88:8036", referrer: "http://xxx"

    上面例子中,if 判断貌似没啥用呀,毕竟我们的变量是写死的。然后 SSI 又不能动态接收参数,其实呀,使用 PHP 套上静态页面就可以接收参数了嘛。还是先准备一个 lcoation 来进行测试。

    location ^~ /ssiphp/ {
      alias html/ssi/;
      fastcgi_pass unix:/var/sock/php-fpm/www.sock;
      fastcgi_index  index.php;
      fastcgi_param  SCRIPT_FILENAME $request_filename;
      include        fastcgi_params;
      ssi on;
    }

    然后,准备一个 if.php 文件。

    <?php
    $age = $_GET['age'];
    ?>
    <!--# set var="age" value="<?php echo $age;?>" -->
    <!--# if expr="$age = 37" -->
    37
    <!--# elif expr="$age != 40" -->
    not 40
    <!--# else -->
    old or young? old!
    <!--# endif -->

    测试一下吧,看看 if 的效果怎么样。

    ➜  ~ curl "http://192.168.56.88:8036/ssiphp/if.php?age=37"
    
    
    37
    
    
    ➜  ~ curl "http://192.168.56.88:8036/ssiphp/if.php?age=49"
    
    
    not 40
    
    
    ➜  ~ curl "http://192.168.56.88:8036/ssiphp/if.php?age=40"
    
    
    old or young? old!

    返回的结果和我们 if 条件的预期一样。不过需要注意的是,这里的 if 判断条件没有大于、小于,只有等于、不等于、空或非空判断,但判断值可以是正则表达式。

    总结

    有意思吧,哈哈,早期的我们就是靠这个,实现 ASP 开发中头文件和脚文件的拆分的。不过现在真的很少见到了,毕竟一是纯静态网站已经很少了,二是各种语言框架都已经自带这些功能了。即使是做文章站那种生成纯静态页面的,也是直接去生成整张页面,和这个嵌套也没啥关系。


    因此,它的应用场景现在确实很有限了。大家了解一下就好,特别是各位年轻的大佬,如果没见过的话,自己试试,其实也挺好玩的。


    参考文档:


    http://nginx.org/en/docs/http/ngx_http_ssi_module.html

    视频链接

    微信文章地址:https://mp.weixin.qq.com/s/cjLWGLGIl52anJx8W1NKsQ

    B站视频地址:https://www.bilibili.com/video/BV12c411k7yC/

    搜索
    关注