Nginx(二十)nginx配置perl

一    嵌入式Perl模块(Embedded Perl)

如果对于一个'绝大部分'内容是'静态'的网站,只有'极少数'的地方需要动态显示,碰巧你'又了解'一点perl知识,那么'nginx + perl'的结合就能很好解决问题

Nginx'并不提供'支持对'外部程序'的直接调用或者解析,所有的'外部程序(perl,python)'必须通过'fastcgi接口'来调用;这里'使用perl-fcgi'来使用nginx支持cgi

①  yum安装模块 

++++++++'nginx必须安装相关的perl模块'++++++++

yum -y install perl-devel perl-ExtUtils-Embed

源码安装查看'官方支持'的模块支持'动态加载'

:./configure --help | grep dynamic

备注: 第三方模块需要'源码编辑安装'支持才'可编译成'模块

nginx动态加载模块

嵌入式Perl模块使用

Nginx(二十)nginx配置perl_第1张图片

该ngx_http_perl_module模块用于在Perl中实现'位置和变量'处理程序,并将Perl调用'插入到SSI'中

该模块'不是默认生成的',它应该使用--with-http_perl_module'配置参数启用'

+++++++++'对于rpm安装的nginx,如果安装动态模块直接rpm安装相关的模块即可'+++++++++

yum install nginx-mod-http-perl.x86_64 -y

Nginx(二十)nginx配置perl_第2张图片

Nginx(二十)nginx配置perl_第3张图片

+++++++'记得重启nginx而不是reload'+++++++

systemctl restart nginx

②  源码编译时的参数

--with-http_perl_module  -->'支持perl'

二    nginx使用内置的perl模块

Nginx-Perl配置使用入门

nginx中使用perl模块

其它参考博客

++++++++nginx中'使用perl'有两种方法++++++++

 1)一种是直接'在nginx的配置文件中写'perl代码-->'耦和性'太大,'不建议'

 2)还有一种是把perl脚本'写在外部文件中'

①   把perl脚本写在外部文件

1)由于是'rpm安装'nginx,所以nginx的'默认根目录'为/usr/local/nginx

2)perl'脚本存放的目录'为nginx的根目录下的perl/lib下,'脚本名字'为test.pm

Nginx(二十)nginx配置perl_第4张图片

Nginx(二十)nginx配置perl_第5张图片

nginx关于perl配置含义: 把所有'来自http://nginx.wzj.com/user/'下的'请求'交由'test.pm脚本'中定义的'process方法'来处理

Nginx(二十)nginx配置perl_第6张图片

Nginx(二十)nginx配置perl_第7张图片

'注意': systemctl restart nginx

'访问' http://nginx.wzj.com/user/wzj -->效果'展示'

Nginx(二十)nginx配置perl_第8张图片

②  perl使用nginx

当'使用 use nginx 时',会有'如下的对象可以调用',可以看到上面 'shift 一个对象到 $r 上',然后就可以'用 $r 调用'那些对象了:

$r->args                       – 请求的'参数'
$r->discard_request_body       – 这个参数是让 Nginx '放弃' request 的 'body' 的内容
$r->filename                   – 返回合适的'请求文件的名字'
$r->has_request_body(function) – 如果'没有请求主体',返回'0',但是如果'请求主体存在',那么建立传递的函数并返回1,在程序的最后,nginx将调用指定的处理器
$r->header_in(header)          – 查找'请求头的信息'
$r->header_only                – 如果我们'只要返回'一个'响应'的头
$r->header_out(header, value)  – 设置'响应头'
$r->internal_redirect(uri)     – 使内'部重定向'到指定的URI,重定向仅在'完成perl脚本后'发生.可以使用 header_out(Location….的方法来让浏览器自己重定向
$r->print(args, …)             – 发送数据'给客户端'
$r->request_body               – '得到'客户端'提交'过来的'内容' (body 的参数,可能需要修改 nginx 的 client_body_buffer_size. )
$r->request_body_file          — 给客户的 body 存成文件,并返回文件名
$r->request_method             — 得到'请求' HTTP 'method'
$r->remote_addr                – 得到'客户端的 IP 地址'
$r->rflush                     – '立即'传送数据给客户端
$r->sendfile(file [, displacement [, length ] ) – 传送给客户端指定文件的内容,可选的参数表明只传送数据的偏移量与长度,精确的传递仅在perl脚本执行完毕后生效.这可是所谓的高级功能啊
$r->send_http_header(type)                      – 添加一个'回应的 http 头'的信息
$r->sleep(milliseconds, handler)                – 设置为请求在'指定的时间'使用指定的处理方法和停止处理,在此期间nginx将继续处理其他的请求,'超过指定的时间后',nginx将运行安装的处理方法,'注意'你需要为处理方法通过一个reference,在处理器间转发数据你可以使用$r->variable().
$r->status(code)                                – 设置 http 的'响应码'
$r->unescape(text)                              – 使用 http 方法'加密内容'如 %XX
$r->uri                                         – 得到'请求的 URL'
$r->variable(name[, value])                     – 设置'变量的值'

三    perl + fastcgi + nginx搭建

Centos下Nginx添加perl(fastcgi)支持

Centos下'Nginx添加perl'(fastcgi)支持

理解: perl-FCGI就是对于'perl'的fastcgi

类似: php-fpm就是对于'php'的fastcgi

①   yum安装

Nginx(二十)nginx配置perl_第9张图片

②  新建perl脚本用做fastcgi进程管理

'新建perl'脚本'用做fastcgi进程管理','保存为'/usr/bin/perl-fastcgi.pl

思考: perl的use'加载的模块的路径' -->'/usr/lib64/perl5' -->寻找"${perl_module_name}".pm
#!/usr/bin/perl
 
use FCGI;
use Socket;
use POSIX qw(setsid);
 
require 'syscall.ph';
 
&daemonize;
 
#this keeps the program alive or something after exec'ing perl scripts
END() { } BEGIN() { }
*CORE::GLOBAL::exit = sub { die "fakeexit\nrc=".shift()."\n"; };
eval q{exit};
if ($@) {
    exit unless $@ =~ /^fakeexit/;
};
 
&main;
 
sub daemonize() {
    chdir '/'                 or die "Can't chdir to /: $!";
    defined(my $pid = fork)   or die "Can't fork: $!";
    exit if $pid;
    setsid                    or die "Can't start a new session: $!";
    umask 0;
}
 
sub main {
    # 两种socket的定义方式-->后者'只能是本地'
       # $socket = FCGI::OpenSocket( "127.0.0.1:8999", 10 ); #use IP sockets
       $socket = FCGI::OpenSocket( "/tmp/perl-fastcgi.sock", 10 ); #use IP sockets
        $request = FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%req_params, $socket );
        if ($request) { request_loop()};
            FCGI::CloseSocket( $socket );
}
 
sub request_loop {
        while( $request->Accept() >= 0 ) {
 
           #processing any STDIN input from WebServer (for CGI-POST actions)
           $stdin_passthrough ='';
           $req_len = 0 + $req_params{'CONTENT_LENGTH'};
           if (($req_params{'REQUEST_METHOD'} eq 'POST') && ($req_len != 0) ){
                my $bytes_read = 0;
                while ($bytes_read < $req_len) {
                        my $data = '';
                        my $bytes = read(STDIN, $data, ($req_len - $bytes_read));
                        last if ($bytes == 0 || !defined($bytes));
                        $stdin_passthrough .= $data;
                        $bytes_read += $bytes;
                }
            }
 
            #running the cgi app
            if ( (-x $req_params{SCRIPT_FILENAME}) &&  #can I execute this?
                 (-s $req_params{SCRIPT_FILENAME}) &&  #Is this file empty?
                 (-r $req_params{SCRIPT_FILENAME})     #can I read this file?
            ){
        pipe(CHILD_RD, PARENT_WR);
        my $pid = open(KID_TO_READ, "-|");
        unless(defined($pid)) {
            print("Content-type: text/plain\r\n\r\n");
                        print "Error: CGI app returned no output - ";
                        print "Executing $req_params{SCRIPT_FILENAME} failed !\n";
            next;
        }
        if ($pid > 0) {
            close(CHILD_RD);
            print PARENT_WR $stdin_passthrough;
            close(PARENT_WR);
 
            while(my $s = ) { print $s; }
            close KID_TO_READ;
            waitpid($pid, 0);
        } else {
                    foreach $key ( keys %req_params){
                       $ENV{$key} = $req_params{$key};
                    }
                    # cd to the script's local directory
                    if ($req_params{SCRIPT_FILENAME} =~ /^(.*)\/[^\/]+$/) {
                            chdir $1;
                    }
 
            close(PARENT_WR);
            close(STDIN);
            #fcntl(CHILD_RD, F_DUPFD, 0);
            syscall(&SYS_dup2, fileno(CHILD_RD), 0);
            #open(STDIN, "<&CHILD_RD");
            exec($req_params{SCRIPT_FILENAME});
            die("exec failed");
        }
            }
            else {
                print("Content-type: text/plain\r\n\r\n");
                print "Error: No such CGI app - $req_params{SCRIPT_FILENAME} may not ";
                print "exist or is not executable by this process.\n";
            }
 
        }
}

③  建立perl-fcgi启动脚本

linux下/etc/init.d目录 和 chkconfig 命令说明

新建'init启动脚本',用于'管理perl-fastcgi',保存为'/etc/init.d/perl-fastcgi'

如果想'简单启动': perl-fastcgi.pl &> dev/null &  -->'不需要下面的启动脚本了'

+++++++++++'chkconfig'+++++++++++

chkconfig: 345 85 15 

说明: 345代表在设置在'那个level中'是'on'的,如果'一个都不想on',那就'写一个横线'"-"

比如: chkconfig: - 85 15

备注: 后面两个数字当然代表'S和K'的默认排序号啦,'都在/etc/rc(0~6).d'中

类似: S85tomcat K15tomcat

++++++++++++'level级别说明'++++++++++++

--level<等级代号>  指定读系统服务要在'哪一个执行等级中'开启或关毕
      等级0表示:表示关机
      等级1表示:单用户模式
      等级2表示:无网络连接的多用户命令行模式
      等级3表示:'有网络'连接的'多用户'命令行模式
      等级4表示:'不可用'
      等级5表示:'带图形界面'的'多用户'模式
      等级6表示:重新启动

      需要'说明'的是

      1)level选项可以指定'要查看的运行级'而'不一定是当前运行级'。

      2)对于'每个运行级',只能有一个'启动'脚本或者'停止'脚本

      3)当'切换'运行级时,init'不会重新启动'已经启动的服务,也不会'再次去停止'已经停止的服务
#!/bin/sh                                                                                                                                                                                                      
#
# perl-fastcgi – this script starts and stops the perl-cgi daemon
#
# chkconfig: - 85 15
# description: FCGI-perl handles perl
# processname: perl-fastcgi

 
# Source function library.
. /etc/rc.d/init.d/functions
 
# Source networking configuration.
. /etc/sysconfig/network
 
# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0
 
perlfastcgi="/usr/bin/perl-fastcgi.pl"
prog=$(basename perl)
 
lockfile=/var/lock/subsys/perl-fastcgi
 
start() {
    [ -x $perlfastcgi ] || exit 5
    echo -n $"Starting $prog: "
    # '后台运行'
    daemon $perlfastcgi
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}
 
stop() {
    echo -n $"Stopping $prog: "
    killproc $prog -QUIT
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}
 
restart() {
    stop
    start
}
 
reload() {
    echo -n $"Reloading $prog: "
    # nginx修改为
    killproc $prog -HUP
    RETVAL=$?
    echo
}
 
force_reload() {
    restart
}
rh_status() {
    status $prog
}
 
rh_status_q() {
    rh_status >/dev/null 2>&1
}
 
case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
        ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
        exit 2
    esac

linux的functions之killproc函数详解

Nginx(二十)nginx配置perl_第10张图片

④  启动perl-fastcgi进程

用指定的用户身份运行程序

chmod +x /usr/bin/perl-fastcgi.pl   -->'可执行权限'

备注1: 要设置'nginx运行用户'和'运行perl_fastcgi.pl'的用户'一致',要不会出现访问/tmp/fastcgi.sock的'权限'问题

备注2: 也可以使用'chmod 666 /tmp/perl-fastcgi.sock' 来给'perl-fastcgi.sock权限'

chmod 755 /etc/init.d/perl-fastcgi  -->'权限' --> 'a+x'也可,确定有'读和执行'权限

/etc/init.d/perl-fastcgi start      -->'启动脚本进行监听'

chkconfig perl-fastcgi on           -->'Centos7保留Centos6的开机自启动方式'

Nginx(二十)nginx配置perl_第11张图片

⑤  nginx中关于perl的配置

文件扩展名为'.perl、.pl、.cgi'的请求,由Nginx'交给Perl(FastCGI)进程'去处理

server
    {
        listen       80;
        server_name nginx.wzj.com; 
   location ~ .*\.(pl|cgi|perl)?$ {
         root  /usr/share/nginx/perl;
         fastcgi_pass    unix:/tmp/perl-fastcgi.sock; '注意: 与上面配置的相同' --> '套接文件形式'
         fastcgi_index   index.perl;
         fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;  
         include         fastcgi_params;  
      }              
      access_log none;
}

⑥  配置perl首页

cat >>/usr/share/nginx/perl/index.perl << EOF
#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "Hello, Perl.";
EOF

⑦  测试效果

Nginx(二十)nginx配置perl_第12张图片

⑧  解决报错

1)fastcgi首页问题

原因: 'fastcgi首页'只能'配置一个',配置多个'报如下的错误'

fastcgi_index   index.cgi index.perl index.pl;  '错误方式'

fastcgi_index   index.perl;                     '正确方式'

2)socket问题导致500报错

Nginx(二十)nginx配置perl_第13张图片

'解决策略': 'socket套接字'涉及'权限'问题,用'监听端口的形式'进行

Nginx(二十)nginx配置perl_第14张图片

'重启nginx': nginx -t && systemctl restart nginx

'重启perl-fastcgi': /etc/init.d/perl-fastcgi restart

Nginx(二十)nginx配置perl_第15张图片

四   参考博客

ngx_http_perl_module

nginx中使用perl模块

Nginx-Perl配置使用入门

perl + fastcgi + nginx搭建

实战Nginx与Perl的配置

perl语言中的.pm文件和.pl文件区别

你可能感兴趣的:(nginx,Perl,perl,nginx)