nginx+perl模块的使用

  • A+
所属分类:系统运维 运维实战

nginx做负载均衡时,多多少少都会有一些自己个性化需求,那么要满足自己的需求,就得修改开发一些模块功能,下来我说一下具体的实现方法

我本人比较喜欢perl开发,所以就用的nginx+perl模块做的一些代码策略实现

首先,需要nginx支持perl模块开发,这很简单,只需要编译nginx的时候加上支持perl模块就行 --with-http_perl_module

其次在讲代码实现之前,我们先了解一下nginx的变量详解,如下:

$args #请求中的参数值
$query_string #同 $args
$arg_NAME #GET请求中NAME的值
$is_args #如果请求中有参数,值为"?",否则为空字符串
$uri #请求中的当前URI(不带请求参数,参数位于$args),可以不同于浏览器传递的$request_uri的值,它可以通过内部重定向,或者使用index指令进行修改,$uri不包含主机名,如"/it/1.html"。
$document_uri #同 $uri
$document_root #当前请求的文档根目录或别名
$host #优先级:HTTP请求行的主机名>"HOST"请求头字段>符合请求的服务器名.请求中的主机头字段,如果请求中的主机头不可用,则为服务器处理请求的服务器名称
$hostname #主机名
$https #如果开启了SSL安全模式,值为"on",否则为空字符串。
$binary_remote_addr #客户端地址的二进制形式,固定长度为4个字节
$body_bytes_sent #传输给客户端的字节数,响应头不计算在内;这个变量和Apache的mod_log_config模块中的"%B"参数保持兼容
$bytes_sent #传输给客户端的字节数
$connection #TCP连接的序列号
$connection_requests #TCP连接当前的请求数量
$content_length #"Content-Length" 请求头字段
$content_type #"Content-Type" 请求头字段
$cookie_name #cookie名称
$limit_rate #用于设置响应的速度限制
$msec #当前的Unix时间戳
$nginx_version #nginx版本
$pid #工作进程的PID
$pipe #如果请求来自管道通信,值为"p",否则为"."
$proxy_protocol_addr #获取代理访问服务器的客户端地址,如果是直接访问,该值为空字符串
$realpath_root #当前请求的文档根目录或别名的真实路径,会将所有符号连接转换为真实路径
$remote_addr #客户端地址
$remote_port #客户端端口
$remote_user #用于HTTP基础认证服务的用户名
$request #代表客户端的请求地址
$request_body #客户端的请求主体:此变量可在location中使用,将请求主体通过proxy_pass,fastcgi_pass,uwsgi_pass和scgi_pass传递给下一级的代理服务器
$request_body_file #将客户端请求主体保存在临时文件中。文件处理结束后,此文件需删除。如果需要之一开启此功能,需要设置client_body_in_file_only。如果将次文件传 递给后端的代理服务器,需要禁用request body,即设置proxy_pass_request_body off,fastcgi_pass_request_body off,uwsgi_pass_request_body off,or scgi_pass_request_body off
$request_completion #如果请求成功,值为"OK",如果请求未完成或者请求不是一个范围请求的最后一部分,则为空
$request_filename #当前连接请求的文件路径,由root或alias指令与URI请求生成
$request_length #请求的长度 (包括请求的地址,http请求头和请求主体)
$request_method #HTTP请求方法,通常为"GET"或"POST"
$request_time #处理客户端请求使用的时间,单位为秒,精度毫秒; 从读入客户端的第一个字节开始,直到把最后一个字符发送给客户端后进行日志写入为止。
$request_uri #这个变量等于包含一些客户端请求参数的原始URI,它无法修改,请查看$uri更改或重写URI,不包含主机名,例如:"/cnphp/test.php?arg=freemouse"
$scheme #请求使用的Web协议,"http" 或 "https"
$server_addr #服务器端地址,需要注意的是:为了避免访问linux系统内核,应将ip地址提前设置在配置文件中
$server_name #服务器名
$server_port #服务器端口
$server_protocol #服务器的HTTP版本,通常为 "HTTP/1.0" 或 "HTTP/1.1"
$status #HTTP响应代码
$time_iso8601 #服务器时间的ISO 8610格式
$time_local #服务器时间(LOG Format 格式)
$cookie_NAME #客户端请求Header头中的cookie变量,前缀"$cookie_"加上cookie名称的变量,该变量的值即为cookie名称的值
$http_NAME #匹配任意请求头字段;变量名中的后半部分NAME可以替换成任意请求头字段,如在配置文件中需要获取http请求头:"Accept-Language",$http_accept_language即可
$http_cookie  
$http_host #请求地址,即浏览器中你输入的地址(IP或域名)
$http_referer #url跳转来源,用来记录从那个页面链接访问过来的
$http_user_agent #用户终端浏览器等信息
$http_x_forwarded_for
$sent_http_NAME #可以设置任意http响应头字段;变量名中的后半部分NAME可以替换成任意响应头字段,如需要设置响应头Content-length,$sent_http_content_length即可
$sent_http_cache_control
$sent_http_connection
$sent_http_content_type
$sent_http_keep_alive
$sent_http_last_modified
$sent_http_location
$sent_http_transfer_encoding

另外:当使用 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]) – 设置变量的值

好,了解了以上参数后,我们开始讲讲怎么简单的使用:

一:nginx加载脚本方式

首先,写一些策略脚本,这种我们用的比较少,这里我们取个官网的例子:

The perl/lib/hello.pm module:

package hello;

use nginx;

sub handler {
my $r = shift;

$r->send_http_header("text/html");
return OK if $r->header_only;

$r->print("hello!\n<br/>");

if (-f $r->filename or -d _) {
$r->print($r->uri, " exists!\n");
}

return OK;
}

1;
__END__
然后nginx配置如下:
http {

perl_modules perl/lib;  ----------------------上面那个脚本的路径
perl_require hello.pm;

server {
location / {
perl hello::handler;
}
}

二:perl设置nginx变量传递,这里我大概说一下如下代码的意思,当时我们业务拆分是需要安装用户分类访问到不通的域名,所有我们这边就把用户的id直接预热到memcached中,然后通过nginx转发时判断读取,主要代码如下:

 

http {

perl_set $str '
sub {
use Cache::Memcached;
my $memd = new Cache::Memcached{servers => ["10.0.58.50:11211"]};
my $r = shift;
my $url= $r->uri;
my $request_uri = $r->variable("request_uri");
my $query_uri = $r->unescape($request_uri);
my $server_uri = $r->variable("server_name");
my $client_uri = $r->variable("remote_addr");
if ($query_uri =~ /uid/){
$query_uri =~ /(uid=)(\d+)/;
my $query_uid=$2;
if ($query_uid > 51879718){

return 1;
}
if (defined($memd->get($query_uid))){
return 1;
}
# warn "***uid in ***".$query_uid."\n";
return 0;
}
if ($query_uri !~ /uid/){
if ($query_uri =~ /userid/){
$query_uri =~ /(userid=)(\d+)/;
my $query_uid=$2;
if ($query_uid < 51879719){
if (defined($memd->get($query_uid))){
return 1;
}
# warn "***userid in coolcloud***".$query_uid."\n";
return 0;
}
return 1;
}
}
}
';

server {

location ~ ^/abc/ds/cgroupcontact {
if ($str = 0) {
proxy_pass http://sss.bbbb.com;
}

proxy_pass http://cccc;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

}

}

  • 安卓客户端下载
  • 微信扫一扫
  • weinxin
  • 微信公众号
  • 微信公众号扫一扫
  • weinxin
avatar