一 嵌入式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模块使用
该ngx_http_perl_module模块用于在Perl中实现'位置和变量'处理程序,并将Perl调用'插入到SSI'中
该模块'不是默认生成的',它应该使用--with-http_perl_module'配置参数启用'
+++++++++'对于rpm安装的nginx,如果安装动态模块直接rpm安装相关的模块即可'+++++++++
yum install nginx-mod-http-perl.x86_64 -y
+++++++'记得重启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关于perl配置含义: 把所有'来自http://nginx.wzj.com/user/'下的'请求'交由'test.pm脚本'中定义的'process方法'来处理
'注意': systemctl restart nginx
'访问' http://nginx.wzj.com/user/wzj -->效果'展示'
② 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安装
② 新建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函数详解
④ 启动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中关于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
⑦ 测试效果
⑧ 解决报错
1)fastcgi首页问题
原因: 'fastcgi首页'只能'配置一个',配置多个'报如下的错误'
fastcgi_index index.cgi index.perl index.pl; '错误方式'
fastcgi_index index.perl; '正确方式'
2)socket问题导致500报错
'解决策略': 'socket套接字'涉及'权限'问题,用'监听端口的形式'进行
'重启nginx': nginx -t && systemctl restart nginx
'重启perl-fastcgi': /etc/init.d/perl-fastcgi restart
四 参考博客
ngx_http_perl_module
nginx中使用perl模块
Nginx-Perl配置使用入门
perl + fastcgi + nginx搭建
实战Nginx与Perl的配置
perl语言中的.pm文件和.pl文件区别