Openresrt最佳案例

第1篇:Nginx介绍

Nginx是一个高性能的Web 服务器,同时是一个高效的反向代理服务器,它仍是一个IMAP/POP3/SMTP 代理服务器。javascript

因为Nginx采用的是事件驱动的架构,可以处理并发百万级别的tcp链接,高度的模块化设计和自由的BSD许可,使得Nginx有着很是丰富的第三方模块。好比Openresty、API网关Kong。php

BSD开源协议是一个给予使用者很大自由的协议。基本上使用者能够”随心所欲”,能够自由的使用,修改源代码,也能够将修改后的代码做为开源或者专有软件再发布。css

Nginx的优势

  • 高并发响应性能很是好,官方Nginx处理静态文件并发5w/s
  • 反向代理性能很是强。(可用于负载均衡)
  • 内存和cpu占用率低。(为Apache的1/5-1/10)
  • 对后端服务有健康检查功能。
  • 支持PHP cgi方式和fastcgi方式。
  • 配置代码简洁且容易上手。

Nginx的安装

Centos系统安装,请参考这里http://www.linuxidc.com/Linux/2016-09/134907.htm。先复制粘贴下它的文章。html

1.gcc 安装

安装 nginx 须要先将官网下载的源码进行编译,编译依赖 gcc 环境,若是没有 gcc 环境,则须要安装:java

yum install gcc-c++node

2.PCRE pcre-devel 安装

PCRE(Perl Compatible Regular Expressions) 是一个Perl库,包括 perl 兼容的正则表达式库。nginx 的 http 模块使用 pcre 来解析正则表达式,因此须要在 linux 上安装 pcre 库,pcre-devel 是使用 pcre 开发的一个二次开发库。nginx也须要此库。命令:mysql

yum install -y pcre pcre-devellinux

3.zlib 安装

zlib 库提供了不少种压缩和解压缩的方式, nginx 使用 zlib 对 http 包的内容进行 gzip ,因此须要在 Centos 上安装 zlib 库。nginx

yum install -y zlib zlib-develc++

4.OpenSSL 安装

OpenSSL 是一个强大的安全套接字层密码库,囊括主要的密码算法、经常使用的密钥和证书封装管理功能及 SSL 协议,并提供丰富的应用程序供测试或其它目的使用。 nginx 不只支持 http 协议,还支持 https(即在ssl协议上传输http),因此须要在 Centos 安装 OpenSSL 库。

yum install -y openssl openssl-devel

5.官网下载

1.直接下载.tar.gz安装包,地址:https://nginx.org/en/download.html

2.使用wget命令下载(推荐)。

wget -c https://nginx.org/download/nginx-1.10.1.tar.gz

6.解压

依然是直接命令:

tar -zxvf nginx-1.10.1.tar.gz cd nginx-1.10.1

7.配置

其实在 nginx-1.10.1 版本中你就不须要去配置相关东西,默认就能够了。固然,若是你要本身配置目录也是能够的。 使用默认配置

./configure

8.编译安装

make make install

查找安装路径:

whereis nginx

Nginx的模块组成

Nginx的模块从结构上分为核心模块、基础模块和第三方模块:

  • 核心模块:HTTP模块、EVENT模块和MAIL模块
  • 基础模块:HTTP Access模块、HTTP FastCGI模块、HTTP Proxy模块和HTTP Rewrite模块,
  • 第三方模块:HTTP Upstream Request Hash模块、Notice模块和HTTP Access Key模块。

Nginx的高并发得益于其采用了epoll模型,与传统的服务器程序架构不一样,epoll是linux内核2.6之后才出现的。Nginx采用epoll模型,异步非阻塞,而Apache采用的是select模型。

  • Select特色:select 选择句柄的时候,是遍历全部句柄,也就是说句柄有事件响应时,select须要遍历全部句柄才能获取到哪些句柄有事件通知,所以效率是很是低。
  • epoll的特色:epoll对于句柄事件的选择不是遍历的,是事件响应的,就是句柄上事件来就立刻选择出来,不须要遍历整个句柄链表,所以效率很是高。

Nginx经常使用命令

nginx 环境变量配置:

export PATH=$PATH:/usr/servers/nginx/sbin

  • 查看nginx进程 ps -ef|grep nginx
  • 启动nginx nginx 启动结果显示nginx的主线程和工做线程,工做线程的数量跟nginx.conf中的配置参数worker_processes有关。
  • 平滑启动nginx kill -HUP cat /var/run/nginx.pid 或者 nginx -s reload
  • 强制中止nginx pkill -9 nginx
  • 检查对nginx.conf文件的修改是否正确 nginx -t
  • 中止nginx的命令 nginx -s stop或者pkill nginx
  • 查看nginx的版本信息 nginx -v
  • 查看完整的nginx的配置信息 nginx -V

Nginx的配置

一般状况下,Nginx的配置在Ngix的安装目录下的/conf/config.default 文件里,基本配置以下:

worker_process # 表示工做进程的数量,通常设置为cpu的核数

worker_connections # 表示每一个工做进程的最大链接数

server{} # 块定义了虚拟主机
    listen # 监听端口
    server_name # 监听域名
    location {} # 是用来为匹配的 URI 进行配置,URI 即语法中的“/uri/”
    location /{} # 匹配任何查询,由于全部请求都以 / 开头
        root # 指定对应uri的资源查找路径,这里html为相对路径,完整路径为
        # /opt/nginx-1.7.7/html/
        index # 指定首页index文件的名称,能够配置多个,以空格分开。若有多
        # 个,按配置顺序查找。

location 经常使用配置以下:

模式 含义
location = /uri = 表示精确匹配,只有彻底匹配上才能生效
location ^~ /uri ^~ 开头对URL路径进行前缀匹配,而且在正则以前。
location ~ pattern 开头表示区分大小写的正则匹配
location ~* pattern 开头表示不区分大小写的正则匹配
location /uri 不带任何修饰符,也表示前缀匹配,可是在正则匹配以后
location / 通用匹配,任何未匹配到其它location的请求都会匹配到,至关于switch中的default

Nginx的经常使用配置很是多,如下内容摘自于布尔教育课件,仅供参考:

#定义Nginx运行的用户和用户组
user  www www;
#启动进程,一般设置成和cpu的数量相等
worker_processes  8;
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;
#为每一个进程分配cpu,上例中将8个进程分配到8个cpu,固然能够写多个,或者将一个进程分配到多个cpu。
worker_rlimit_nofile 102400;
#这个指令是指当一个nginx进程打开的最多文件描述符数目,理论值应该是最多打
#开文件数(ulimit -n)与nginx进程数相除,可是nginx分配请求并非那么均匀
#,因此最好与ulimit -n的值保持一致。

#全局错误日志及PID文件
error_log  /usr/local/nginx/logs/error.log; 
#错误日志定义等级,[ debug | info | notice | warn | error | crit ]
pid        /usr/local/nginx/nginx.pid;

#一个nginx进程打开的最多文件描述符数目,理论值应该是最多打开文件数(系统的值ulimit -n)与nginx进程数相除,可是nginx分配请求并不均匀.
#因此建议与ulimit -n的值保持一致。
worker_rlimit_nofile 65535;

#工做模式及链接数上限
events {
    use   epoll;                #epoll是多路复用IO(I/O Multiplexing)中的一种方式,可是仅用于linux2.6以上内核,能够大大提升nginx的性能
    worker_connections  102400; #单个后台worker process进程的最大并发连接数 (最大链接数=链接数*进程数)
    multi_accept on; #尽量多的接受请求
}
#设定http服务器,利用它的反向代理功能提供负载均衡支持
http {
    #设定mime类型,类型由mime.type文件定义
    include       mime.types;
    default_type  application/octet-stream;
    #设定日志格式
    access_log    /usr/local/nginx/log/nginx/access.log;
     sendfile      on;
    #sendfile 指令指定 nginx 是否调用 sendfile 函数(zero copy 方式)来输出文件,对于普通应用必须设为 on
    #若是用来进行下载等应用磁盘IO重负载应用,可设置为 off,以平衡磁盘与网络I/O处理速度,下降系统的uptime.
    #autoindex  on;  #开启目录列表访问,合适下载服务器,默认关闭。
    tcp_nopush on; #防止网络阻塞
    keepalive_timeout 60;
    #keepalive超时时间,客户端到服务器端的链接持续有效时间,当出现对服务器的后,继请求时,keepalive-timeout功能可避免创建或从新创建链接。
    tcp_nodelay   on; #提升数据的实时响应性
   #开启gzip压缩
   gzip on;
    gzip_min_length  1k;
    gzip_buffers     4 16k;
    gzip_http_version 1.1;
    gzip_comp_level 2; #压缩级别大小,最大为9,值越小,压缩后比例越小,CPU处理更快。
    #值越大,消耗CPU比较高。
    gzip_types       text/plain application/x-javascript text/css application/xml;
    gzip_vary on;
    client_max_body_size 10m;      #容许客户端请求的最大单文件字节数
    client_body_buffer_size 128k;  #缓冲区代理缓冲用户端请求的最大字节数,
    proxy_connect_timeout 90;      #nginx跟后端服务器链接超时时间(代理链接超时)
    proxy_send_timeout 90;         #后端服务器数据回传时间(代理发送超时)
    proxy_read_timeout 90;         #链接成功后,后端服务器响应时间(代理接收超时)
    proxy_buffer_size 4k;          #设置代理服务器(nginx)保存用户头信息的缓冲区大小
    proxy_buffers 4 32k;           #proxy_buffers缓冲区,网页平均在32k如下的话,这样设置
    proxy_busy_buffers_size 64k;   #高负荷下缓冲大小(proxy_buffers*2)
    
    #设定请求缓冲
    large_client_header_buffers  4 4k;
    client_header_buffer_size 4k;
    #客户端请求头部的缓冲区大小,这个能够根据你的系统分页大小来设置,通常一个请求的头部大小不会超过1k
    #不过因为通常系统分页都要大于1k,因此这里设置为分页大小。分页大小能够用命令getconf PAGESIZE取得。
    open_file_cache max=102400 inactive=20s;
    #这个将为打开文件指定缓存,默认是没有启用的,max指定缓存数量,建议和打开文件数一致,inactive是指通过多长时间文件没被请求后删除缓存。
    open_file_cache_valid 30s;
    #这个是指多长时间检查一次缓存的有效信息。
    open_file_cache_min_uses 1;
    #open_file_cache指令中的inactive参数时间内文件的最少使用次数,若是超过这个数字,文件描述符一直是在缓存中打开的,如上例,若是有一个文件在inactive
    #包含其它配置文件,如自定义的虚拟主机
    include vhosts.conf;
}

配置详解2以下:

#这里为后端服务器wugk应用集群配置,根据后端实际状况修改便可,tdt_wugk为负载均衡名称,能够任意指定
    #但必须跟vhosts.conf虚拟主机的pass段一致,不然不能转发后端的请求。weight配置权重,在fail_timeout内检查max_fails次数,失败则剔除均衡。
    upstream tdt_wugk {
        server   127.0.0.1:8080 weight=1 max_fails=2 fail_timeout=30s;
        server   127.0.0.1:8081 weight=1 max_fails=2 fail_timeout=30s;
    }
   #虚拟主机配置
    server {
        #侦听80端口
        listen       80;
        #定义使用www.wuguangke.cn访问
        server_name  www.wuguangke.cn;
        #设定本虚拟主机的访问日志
        access_log  logs/access.log  main;
            root   /data/webapps/wugk;  #定义服务器的默认网站根目录位置
        index index.php index.html index.htm;   #定义首页索引文件的名称
        #默认请求
        location ~ /{
          root   /data/www/wugk;      #定义服务器的默认网站根目录位置
          index index.php index.html index.htm;   #定义首页索引文件的名称
          #如下是一些反向代理的配置.
          proxy_next_upstream http_502 http_504 error timeout invalid_header;
          #若是后端的服务器返回50二、50四、执行超时等错误,自动将请求转发到upstream负载均衡池中的另外一台服务器,实现故障转移。
          proxy_redirect off;
          #后端的Web服务器能够经过X-Forwarded-For获取用户真实IP
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
           proxy_pass  http://tdt_wugk;     #请求转向后端定义的均衡模块
       }
       
        # 定义错误提示页面
            error_page   500 502 503 504 /50x.html;  
            location = /50x.html {
            root   html;
        }
        #配置Nginx动静分离,定义的静态页面直接从Nginx发布目录读取。
        location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|txt|js|css)$
        {
            root /data/www/wugk;
            #expires定义用户浏览器缓存的时间为3天,若是静态页面不常更新,能够设置更长,这样能够节省带宽和缓解服务器的压力。
            expires      3d;
        }
        #PHP脚本请求所有转发到 FastCGI处理. 使用FastCGI默认配置.
        location ~ \.php$ {
            root /root;
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME /data/www/wugk$fastcgi_script_name;
            include fastcgi_params;
        }
        #设定查看Nginx状态的地址
        location /NginxStatus {
            stub_status  on;
        }
     }
}

Nginx 内置绑定变量

名称 说明
$arg_name 请求中的name参数
$args 请求中的参数
$binary_remote_addr 远程地址的二进制表示
$body_bytes_sent 已发送的消息体字节数
$content_length HTTP 请求信息里的”Content-Length”
$content_type 请求信息里的”Content-Type”
$document_root 针对当前请求的根路径设置值
\(document_uri | 与\)uri相同; 好比 /test2/test.php
$host 请求信息中的”Host”,若是请求中没有Host行,则等于设置的服务器名
$hostname 机器名使用 gethostname系统调用的值
$http_cookie cookie 信息
$http_referer 引用地址
$http_user_agent 客户端代理信息
$http_via 最后一个访问服务器的Ip地址。
$http_x_forwarded_for 至关于网络访问路径
$is_args 若是请求行带有参数,返回“?”,不然返回空字符串
$limit_rate 对链接速率的限制
$nginx_version 当前运行的nginx版本号
$pid worker 进程的PID
\(query_string | 与\)args相同
\(realpath_root | 按root指令或alias指令算出的当前请求的绝对路径。其中的符号连接都会解析成真是文件路径,使用 Nginx 内置绑定变量 | | 207\)remote_addr 客户端IP地址
$remote_port 客户端端口号
$remote_user 客户端用户名,认证用
$request 用户请求
$request_body 这个变量(0.7.58+) 包含请求的主要信息。在使用proxy_pass或fastcgi_pass指令的location中比较有意义
$request_body_file 客户端请求主体信息的临时文件名
$request_completion 若是请求成功,设为”OK”;若是请求未完成或者不是一系列请求中最后一部分则设为空
$request_filename 当前请求的文件路径名,好比/opt/nginx/www/test.php
$request_method 请求的方法,好比”GET”、”POST”等
$request_uri 请求的URI,带参数
$scheme 所用的协议,好比http或者是https
$server_addr 服务器地址,若是没有用listen指明服务器地址,使用这个变量将发起一次系统调用以取得地址(形成资源浪费)
$server_name 请求到达的服务器名
$server_port 请求到达的服务器端口号
$server_protocol 请求的协议版本,”HTTP/1.0”或”HTTP/1.1”
$uri 请求的URI,可能和最初的值有不一样,好比通过重定向之类的

第2篇:Lua入门

Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

Lua 是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组,由Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo所组成并于1993年开发。 —摘抄 http://www.runoob.com/lua/lua-tutorial.html

环境搭建

注意: 在上一篇文章中,OpenResty已经有了Lua的环境,这里安装的是单独的Lua环境,用于学习和开发Lua。大多数的电脑是Windowds版本的电脑,Windows版本下载地址http://luaforge.net/projects/luaforwindows/。

Linux和Mac电脑下载地址:http://luajit.org/download.html,安装命令以下:

wget http://luajit.org/download/LuaJIT-2.1.0-beta1.tar.gz

tar -xvf LuaJIT-2.1.0-beta1.tar.gz
cd LuaJIT-2.1.0-beta1
make
sudo make install

使用IDEA开发的同窗,能够经过安装插件的形式来集成Lua的环境,插件名为EmmyLua,安装插件后,在Idea的右侧栏就会出现Lua的图标,点击图标,就会出现运行Lua代码的窗口。建议使用该插件,能够免去安装Lua环境的麻烦。

第一个Lua程序

安装好环境后,我采用EmmyLua插件的形式,对Lua的入门语法进行一个简单的讲解。 打开EmmyLua的终端,在终端上输入:

print("hi you")

按ctrl+enter,终端显示:

hi you

Lua基本数据类型

lua的基本数据类型有nil、string、boolean、number、function类型。

nil 类型

nil相似于Java中的null ,表示空值。变量第一次赋值为nil。

local num
print(num)
num=100
print(num)

终端输出:

nil

100

number (数字)

Number 类型用于表示实数,和 Java里面的 double 类型很相似。可使用数学函数 math.floor(向下取整) 和 math.ceil(向上取整) 进行取整操做。

local order = 3.99
local score = 98.01
print(math.floor(order))
print(math.ceil(score))

输出:

3

99

string 字符串

Lua 中有三种方式表示字符串: 一、使用一对匹配的单引号。例:’hello’。 二、使用一对匹配的双引号。例:”abclua 3.字符串还能够用一种长括号(即[[ ]]) 括起来的方式定义

ocal str1 = 'hello world'
local str2 = "hello lua"
local str3 = [["add\name",'hello']]
local str4 = [=[string have a [[]].]=]
print(str1) -->output:hello world
print(str2) -->output:hello lua
print(str3) -->output:"add\name",'hello'
print(str4) --

table (表)

Table 类型实现了一种抽象的“关联数组”。“关联数组”是一种具备特殊索引方式的数组,索引一般是字符串(string) 或者 number 类型,但也能够是除 nil 之外的任意类型的值。

local corp = {
    web = "www.google.com", --索引为字符串,key = "web",
                              -- value = "www.google.com"
    telephone = "12345678", --索引为字符串
    staff = {"Jack", "Scott", "Gary"}, --索引为字符串,值也是一个表
    100876, --至关于 [1] = 100876,此时索引为数字
            -- key = 1, value = 100876
    100191, --至关于 [2] = 100191,此时索引为数字
    [10] = 360, --直接把数字索引给出
    ["city"] = "Beijing" --索引为字符串
}

print(corp.web) -->output:www.google.com
print(corp["telephone"]) -->output:12345678
print(corp[2]) -->output:100191
print(corp["city"]) -->output:"Beijing"
print(corp.staff[1]) -->output:Jack
print(corp[10]) -->output:36

function(函数)

在 Lua 中,函数 也是一种数据类型,函数能够存储在变量中,能够经过参数传递给其余函 数,还能够做为其余函数的返回值。

local function foo()
   print("in the function")
   --dosomething()
   local x = 10
   local y = 20
   return x + y
end
local a = foo --把函数赋给变量
print(a())

--output:
in the function
30

表达式

~= 不等于

逻辑运算符 说明
and 逻辑与
or 逻辑或
not 逻辑非
  • a and b 若是 a 为 nil,则返回 a,不然返回 b;
  • a or b 若是 a 为 nil,则返回 b,不然返回 a。
local c = nil
local d = 0
local e = 100
print(c and d) -->打印 nil
print(c and e) -->打印 nil
print(d and e) -->打印 100
print(c or d) -->打印 0
print(c or e) -->打印 100
print(not c) -->打印 true
print(not d) --> 打印 false

在 Lua 中链接两个字符串,可使用操做符“..”(两个点).

print("Hello " .. "World") -->打印 Hello World
print(0 .. 1) -->打印 01

控制语句

单个 if 分支 型

x = 10
if x > 0 then
    print("x is a positive number")
end

两个分支 if-else 型

x = 10
if x > 0 then
    print("x is a positive number")
else
    print("x is a non-positive number")
end

多个分支 if-elseif-else 型:

score = 90
if score == 100 then
    print("Very good!Your score is 100")
elseif score >= 60 then
    print("Congratulations, you have passed it,your score greater or equal to 60")
    --此处能够添加多个elseif
else
    print("Sorry, you do not pass the exam! ")
end

for 控制结构

Lua 提供了一组传统的、小巧的控制结构,包括用于条件判断的 if 用于迭代的 while、repeat 和 for,本章节主要介绍 for 的使用.

for 数字型

for 语句有两种形式:数字 for(numeric for) 和范型 for(generic for) 。 数字型 for 的语法以下:

for var = begin, finish, step do
--body
end

实例1:

for i = 1, 5 do
    print(i)
end
-- output:
1 2 3 4 5

实例2:

for i = 1, 10, 2 do
    print(i)
end
-- output:
1 3 5 7 9

for 泛型

泛型 for 循环经过一个迭代器(iterator) 函数来遍历全部值:

-- 打印数组a的全部值

local a = {"a", "b", "c", "d"}
for i, v in ipairs(a) do
    print("index:", i, " value:", v)
end

-- output:
index: 1 value: a
index: 2 value: b
index: 3 value: c
index: 4 value: d

lua的入门就到这里,由于lua语法虽少,但细节有不少,不可能花不少时间去研究这个。入个门,遇到问题再去查资料就好了。另外须要说明的是本文大部份内容为复制粘贴于OPenResty 最佳实践,感谢原做者的开源电子书,让我获益匪浅。更多内容请参考:

lua入门教程:http://www.runoob.com/lua/lua-tutorial.html

OPenResty 最佳实践: https://moonbingbing.gitbooks.io/openresty-best-practices/content/index.html

第3篇:Openresty的安装

个人服务器为一台全新的centos 7的服务器,因此从头安装openresty,并记录了安装过程当中出现的问题,以及解决办法。

1.首先安装openresty

cd /usr
mkdir servers
mkdir downloads 

yum install libreadline-dev libncurses5-dev libpcre3-dev libssl-dev perl 
 
cd /usr/servers
 
wget https://openresty.org/download/openresty-1.11.2.4.tar.gz
tar -zxvf openresty-1.11.2.4.tar.gz
cd /usr/servers/bunble/LuaJIT-2.1-20170405

安装Lua
make clean && make && make install

安装过程当中出现如下的错误:

gcc: Command not found

2.安装gcc

yum -y install gcc automake autoconf libtool make

3.从新make

make clean && make && make install

ln -sf luajit-2.1.0-alpha /usr/local/bin/luajit

4.下载ngx_cache_purge模块,该模块用于清理nginx缓存

cd /usr/servers/ngx_openresty–1.11.2.4/bundle
wget https://github.com/FRiCKLE/ngx_cache_purge/archive/2.3.tar.gz
tar -xvf 2.3.tar.gz

5.下载nginx_upstream_check_module模块,该模块用于ustream健康检查

cd /usr/servers/ngx_openresty-1.11.2.4/bundle
wget https://github.com/yaoweibin/nginx_upstream_check_module/archive/v0.3.0.tar.gz
tar -xvf v0.3.0.tar.gz

6.从新安装opresty

cd /usr/servers/ngx_openresty-1.11.2.4

./configure --prefix=/usr/servers --with-http_realip_module  --with-pcre  --with-luajit --add-module=./bundle/ngx_cache_purge-2.3/ --add-module=./bundle/nginx_upstream_check_module-0.3.0/ -j2

提示错误,安装pcre库

yum install -y pcre pcre-devel

<1> gcc 安装 安装 nginx 须要先将官网下载的源码进行编译,编译依赖 gcc 环境,若是没有 gcc 环境,则须要安装:

yum install gcc-c++

<2> PCRE pcre-devel 安装

PCRE(Perl Compatible Regular Expressions) 是一个Perl库,包括 perl 兼容的正则表达式库。nginx 的 http 模块使用 pcre 来解析正则表达式,因此须要在 linux 上安装 pcre 库,pcre-devel 是使用 pcre 开发的一个二次开发库。nginx也须要此库。命令:

yum install -y pcre pcre-devel

<3> zlib 安装 zlib 库提供了不少种压缩和解压缩的方式, nginx 使用 zlib 对 http 包的内容进行 gzip ,因此须要在 Centos 上安装 zlib 库。

yum install -y zlib zlib-devel

<4> OpenSSL 安装 OpenSSL 是一个强大的安全套接字层密码库,囊括主要的密码算法、经常使用的密钥和证书封装管理功能及 SSL 协议,并提供丰富的应用程序供测试或其它目的使用。 nginx 不只支持 http 协议,还支持 https(即在ssl协议上传输http),因此须要在 Centos 安装 OpenSSL 库。

yum install -y openssl openssl-devel

<5>.从新安装OpenResty

cd /usr/servers/ngx_openresty-1.11.2.4

./configure --prefix=/usr/servers --with-http_realip_module  --with-pcre  --with-luajit --add-module=./bundle/ngx_cache_purge-2.3/ --add-module=./bundle/nginx_upstream_check_module-0.3.0/ -j2 

make && make install

<6>.启动Nginx

/usr/servers/nginx/sbin/nginx

浏览器访问http://116.196.177.123:

Welcome to OpenResty!

If you see this page, the OpenResty web platform is successfully installed and working. Further configuration is required.

For online documentation and support please refer to openresty.org.

Thank you for flying OpenResty.

安装成功了。

6.配置nginx

vim /usr/servers/nginx/conf/nginx.conf

错误提示没有安装vim

yum -y install vim*

一、在http部分添加以下配置

lua模块路径,多个之间”;”分隔,其中”;;”表示默认搜索路径,默认到/usr/servers/nginx下找

lua_package_path “/usr/servers/lualib/?.lua;;”; #lua 模块
lua_package_cpath “/usr/servers/lualib/?.so;;”; #c模块

二、在nginx.conf中的http部分添加include lua.conf包含此文件片断 Java代码 收藏代码 include lua.conf;

在/usr/server/nginx/conf下

vim lua.conf

#lua.conf  
server {  
    listen       80;  
    server_name  _;  
    
    location /lua {  
    default_type 'text/html';  
        content_by_lua 'ngx.say("hello world")';  
    } 
}

7.环境变量:

vim /etc/profile

JAVA_HOME=/usr/local/jdk/jdk1.8.0_144
JRE_HOME=$JAVA_HOME/jre
PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin
CLASSPATH=:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib/dt.jar
export JAVA_HOME JRE_HOME PATH CLASSPATH
export PATH=$PATH:/usr/servers/nginx/sbin

source /etc/profile

测试:

nginx -t

nginx: the configuration file /usr/servers/nginx/conf/nginx.conf syntax is ok nginx: configuration file /usr/servers/nginx/conf/nginx.conf test is successful

nginx -s reload

浏览器访问http://116.196.177.123/lua ,浏览器显示:

hello world

8.将Lua项目化:

mkdir /usr/example cp -r /usr/servers/lualib/ /usr/example/ mkdir /usr/example/lua

cd /usr/example vim example.conf

server {  
    listen       80;  
    server_name  _;  
  
    location /lua {  
        default_type 'text/html';  
        lua_code_cache off;  
        content_by_lua_file /usr/example/lua/test.lua;  
    }  
}

vim /usr/example/lua/test.lua

ngx.say("hello world");

cd /usr/servers/nginx/conf/

vim nginx.conf

http模块:

http {
    include       mime.types;
    default_type  application/octet-stream;
    lua_package_path "/usr/example/lualib/?.lua;;";  #lua 模块  
    lua_package_cpath "/usr/example/lualib/?.so;;";  #c模块   
    include /usr/example/example.conf;
 ....
 ....

}

nginx -t

nginx: [alert] lua_code_cache is off; this will hurt performance in /usr/example/example.conf:7 nginx: the configuration file /usr/servers/nginx/conf/nginx.conf syntax is ok nginx: configuration file /usr/servers/nginx/conf/nginx.conf test is successful

nginx -s reload

浏览器访问http://116.196.177.123/lua ,

hello world

导出history的全部命令:

在你的帐户目录下    输入命令
ls -a   
找到 .bash_history
这个就是记录命令文件。
输入命令:
cat   .bash_history >> history.txt

参考资料

http://www.linuxidc.com/Linux/2016-09/134907.htm

http://jinnianshilongnian.iteye.com/blog/2186270

https://openresty.org/en/

第4篇:OpenResty常见的api

这篇文章主要讲解OpenResty常见的api。

vim /usr/example/example.conf

location /lua_var {
        default_type 'text/plain';
        content_by_lua_block {
         ngx.say(ngx.var.arg_a)
        }
   }

从新加载nginx配置文件: nginx -s reload

在浏览器上访问http://116.196.177.123/lua_var?a=323,浏览器显示:

323

在上述代码中,涉及到了2个api, 一是ngx.say(直接返回请求结果);二是ngx.var,它是获取请求的参数,好比本例子上的?a=323,获取以后,直接输出为请求结果。

获取请求类型

vim /usr/example/example.conf

location /lua_request{
       default_type 'text/html';
       lua_code_cache off;
       content_by_lua_file  /usr/example/lua/lua_request.lua;
   }

vim /usr/example/lua/lua_request.lua ,添加一下代码:

local arg = ngx.req.get_uri_args()
for k,v in pairs(arg) do
   ngx.say("[GET ] key:", k, " v:", v)
end

ngx.req.read_body() -- 解析 body 参数以前必定要先读取 body
local arg = ngx.req.get_post_args()
for k,v in pairs(arg) do
   ngx.say("[POST] key:", k, " v:", v)
end

在上述例子中有如下的api:

  • ngx.req.get_uri_args 获取在uri上的get类型参数,返回的是一个table类型的数据结构。
  • ngx.req.read_body 读取body,这在解析body以前,必定要先读取body。
  • ngx.req.get_post_args 获取form表单类型的参数,返回结果是一个table类型的数据。

使用curl模拟请求:

curl ‘http://116.196.177.123/lua_request?a=323&b=ss’ -d ‘c=12w&d=2se3’

返回的结果:

[GET ] key:b v:ss
[GET ] key:a v:323
[POST] key:d v:2se3
[POST] key:c v:12w

获取请求头

vim /usr/example/lua/lua_request.lua ,在原有的代码基础上,再添加一下代码:

local headers = ngx.req.get_headers()
ngx.say("headers begin", "<br/>")
ngx.say("Host : ", headers["Host"], "<br/>")
ngx.say("user-agent : ", headers["user-agent"], "<br/>")
ngx.say("user-agent : ", headers.user_agent, "<br/>")
for k,v in pairs(headers) do
    if type(v) == "table" then
        ngx.say(k, " : ", table.concat(v, ","), "<br/>")
    else
        ngx.say(k, " : ", v, "<br/>")
    end
end

从新加载nginx -s reload

使用curl模拟请求:

curl ‘http://116.196.177.123/lua_request?a=323&b=ss’ -d ‘c=12w&d=2se3’

[GET ] key:b v:ss
[GET ] key:a v:323
[POST] key:d v:2se3
[POST] key:c v:12w
headers begin<br/>
Host : 116.196.77.157<br/>
user-agent : curl/7.53.0<br/>
user-agent : curl/7.53.0<br/>
host : 116.196.77.157<br/>
content-type : application/x-www-form-urlencoded<br/>
accept : */*<br/>
content-length : 12<br/>
user-agent : curl/7.53.0<br/>

获取http的其余方法

vim /usr/example/lua/lua_request.lua ,在原有的代码基础上,再添加一下代码:

ngx.say("ngx.req.http_version : ", ngx.req.http_version(), "<br/>")  
--请求方法  
ngx.say("ngx.req.get_method : ", ngx.req.get_method(), "<br/>")  
--原始的请求头内容  
ngx.say("ngx.req.raw_header : ",  ngx.req.raw_header(), "<br/>")  
--请求的body内容体  
ngx.say("ngx.req.get_body_data() : ", ngx.req.get_body_data(), "<br/>")  
ngx.say("<br/>")

从新加载nginx -s reload

使用curl模拟请求:

curl ‘http://116.196.177.123/lua_request?a=323&b=ss’ -d ‘c=12w&d=2se3’

//....
ngx.req.http_version : 1.1<br/>
ngx.req.get_method : POST<br/>
ngx.req.raw_header : POST /lua_request?a=323&b=ss HTTP/1.1
Host: 116.196.77.157
User-Agent: curl/7.53.0
Accept: */*
Content-Length: 12

输出响应

vim /usr/example/example.conf,添加一个location,代码以下:

location /lua_response{
        default_type 'text/html';
        lua_code_cache off;
        content_by_lua_file /usr/example/lua/lua_response.lua ;
  }

vim /usr/example/lua/lua_response.lua 添加一下代码:

ngx.header.a="1"
ngx.header.b={"a","b"}
ngx.say("hello","</br>")
ngx.print("sss")
return ngx.exit(200)

上述代码中有如下api:

  • ngx.header 向响应头输出内容
  • ngx.say 输出响应体
  • ngx.print输出响应体
  • ngx.exit 指定http状态码退出

使用curl模拟请求, curl ‘http://116.196.177.123/lua_response’ ,获取的响应体以下:

hello
sss

日志输出

在配置文件vim /usr/example/example.conf 加上如下代码:

location /lua_log{
       default_type 'text/html';
       lua_code_cache off;
       content_by_lua_file  /usr/example/lua/lua_log.lua;
  }

vim /usr/example/lua/lua_log.lua ,加上如下代码:

local log="i'm log"
local num =10
ngx.log(ngx.ERR, "log",log)
ngx.log(ngx.INFO,"num:" ,num)

从新加载配置文件nginx -s reload

curl ‘http://116.196.177.123/lua_log’

打开nginx 的logs目录下的error.log 文件:

tail -fn 1000 /usr/servers/nginx/logs/error.log

能够看到在日志文件中已经输出了日志,这种日志主要用于记录和测试。

日志级别:

  • ngx.STDERR – 标准输出
  • ngx.EMERG – 紧急报错
  • ngx.ALERT – 报警
  • ngx.CRIT – 严重,系统故障,触发运维告警系统
  • ngx.ERR – 错误,业务不可恢复性错误
  • ngx.WARN – 告警,业务中可忽略错误
  • ngx.NOTICE – 提醒,业务比较重要信息
  • ngx.INFO – 信息,业务琐碎日志信息,包含不一样状况判断等
  • ngx.DEBUG – 调试

内部调用

vim /usr/example/example.conf 添加如下代码:

location /lua_sum{
      # 只容许内部调用
      internal;
      # 这里作了一个求和运算只是一个例子,能够在这里完成一些数据库、
      # 缓存服务器的操做,达到基础模块和业务逻辑分离目的
      content_by_lua_block {
         local args = ngx.req.get_uri_args()
         ngx.say(tonumber(args.a) + tonumber(args.b))
      }
  }

internal 关键字,表示只容许内部调用。使用curl模拟请求,请求命令以下:

$ curl ‘http://116.196.177.123/lua_sum?a=1&b=2’

因为该loction是一个内部调用的,外部不能返回,最终返回的结果为404,以下:

<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>openresty/1.11.2.4</center>
</body>
</html>

vim /usr/example/example.conf 添加如下代码:

location = /lua_sum_test {
   content_by_lua_block {
      local res = ngx.location.capture("/lua_sum", {args={a=3, b=8}})
      ngx.say("status:", res.status, " response:", res.body)
   }  
}

上述的代码经过ngx.location.capture去调用内部的location,并得到返回结果,最终将结果输出,采用curl模拟请求:

$ curl ‘http://116.196.177.123/lua_sum_test’

返回结果以下:

status:200 response:11

重定向

vim /usr

location /lua_redirect{
    default_type 'text/html';
    content_by_lua_file  /usr/example/lua/lua_redirect.lua;
}  
ngx.redirect("http://www.fangzhipeng.com", 302)

http://116.196.177.123/lua_redirect

共享内存

vim /usr/servers/nginx/cong/nginx.conf

在http模块加上如下:

lua_shared_dict shared_data 1m;
 location /lua_shared_dict{
     default_type 'text/html';
     content_by_lua_file /usr/example/lua/lua_shared_dict.lua;
  }
local shared_data = ngx.shared.shared_data
local i = shared_data:get("i")
if not i then
  i = 1
  shared_data:set("i",i)
end
i = shared_data:incr("i",1)
ngx.say("i:",i)

屡次访问 http://116.196.177.123/lua_shared_dict,浏览器打印:

i:1
i:2
i:3
i:4
i:5

OpenResty执行阶段的概念

如下内容来自于《openresty 最佳实践》

微信截图_20170929150427.png

如上图所示,openresty的执行阶段分为

这样咱们就能够根据咱们的须要,在不一样的阶段直接完成大部分典型处理了。

  • set_by_lua* : 流程分支处理判断变量初始化
  • rewrite_by_lua* : 转发、重定向、缓存等功能(例如特定请求代理到外网)
  • access_by_lua* : IP 准入、接口权限等状况集中处理(例如配合 iptable 完成简单防火墙)
  • content_by_lua* : 内容生成
  • header_filter_by_lua* : 响应头部过滤处理(例如添加头部信息)
  • body_filter_by_lua* : 响应体过滤处理(例如完成应答内容统一成大写)

执行阶段概念:

  • log_by_lua* : 会话完成后本地异步完成日志记录(日志能够记录在本地,还能够同步到其 他机器) 实际上咱们只使用其中一个阶段
  • content_by_lua* ,也能够完成全部的处理。但这样作,会让 咱们的代码比较臃肿,越到后期愈加难以维护。把咱们的逻辑放在不一样阶段,分工明确,代 码独立,后期发力能够有不少有意思的玩法。

第5篇:http和C_json模块

Openresty没有提供默认的Http客户端,须要下载第三方的http客户端。

下载lua-resty-http到lualib目录下,使用如下的命令下载:

cd /usr/example/lualib/resty/  
wget https://raw.githubusercontent.com/pintsized/lua-resty-http/master/lib/resty/http_headers.lua  

wget https://raw.githubusercontent.com/pintsized/lua-resty-http/master/lib/resty/http.lua

lua-resty-http模块的地址为https://github.com/pintsized/lua-resty-http

安装成功后,经过require(“resty.http”)引入 lua_http模块,它有如下的api方法:

  • syntax: httpc = http.new() 建立一个 http对象
  • syntax: res, err = httpc:request_uri(uri, params)根据参数获取内容,包括:
    • status 状态码
    • headers 响应头
    • body 响应体

vim /usr/example/lua/test_http.lua,写如下代码:

local http = require("resty.http")  

local httpc = http.new()  
  
local resp, err = httpc:request_uri("http://s.taobao.com", {  
    method = "GET",  
    path = "/search?q=hello",  
    headers = {  
        ["User-Agent"] = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.111 Safari/537.36"  
    }  
})  
  
if not resp then  
    ngx.say("request error :", err)  
    return  
end  
  
 
ngx.status = resp.status  
  
  
for k, v in pairs(resp.headers) do  
    if k ~= "Transfer-Encoding" and k ~= "Connection" then  
        ngx.header[k] = v  
    end  
end  
  
ngx.say(resp.body)  
  
httpc:close()

vim /usr/example/example.conf 加上如下的配置:

location /lua_http {
   default_type 'text/html';
   lua_code_cache on;
   content_by_lua_file /usr/example/lua/test_http.lua;
 }

在Nginx的配置文件nginx.conf的http部分,加上如下dns解析:

vim /usr/servers/nginx/conf/nginx.conf

resolver 8.8.8.8;

浏览器访问:http://116.196.177.123/lua_http,浏览器会显示淘宝的搜索页。

lua_cjson模块

Json是一种常见的数据交换格式,经常使用于http通讯协议和其余数据传输领域。在openresty默认内嵌了lua_cjson模块,用来序列化数据。

lua_cjson模块的地址:https://www.kyne.com.au/~mark/software/lua-cjson-manual.html

它经常使用的API以下:

  • local cjson = require “cjson” 获取一个cjson对象
  • local str = cjson.encode(obj) obj转换成string
  • local obj = cjson.decode(str) 将string转obj

vim /usr/example/lua/test_cjson.lua,添加如下内容:

local cjson = require("cjson")  
  

local obj = {  
    id = 1,  
    name = "zhangsan",  
    age = nil,  
    is_male = false,  
    hobby = {"film", "music", "read"}  
}  
  
local str = cjson.encode(obj)  
ngx.say(str, "<br/>")  
  
 
str = '{"hobby":["film","music","read"],"is_male":false,"name":"zhangsan","id":1,"age":null}'  
local obj = cjson.decode(str)  
  
ngx.say(obj.age, "<br/>")  
ngx.say(obj.age == nil, "<br/>")  
ngx.say(obj.age == cjson.null, "<br/>")  
ngx.say(obj.hobby[1], "<br/>")

vim /usr/example/example.conf添加如下内容:

location ~ /lua_cjson {  
   default_type 'text/html';  
   lua_code_cache on;  
   content_by_lua_file /usr/example/lua/test_cjson.lua;  
 }

在浏览器上访问http://116.196.177.123/lua_cjson,浏览器显示如下内容:

{"hobby":["film","music","read"],"is_male":false,"name":"zhangsan","id":1}
null
false
true
film

第6篇:OpenResty链接Mysql

Centos系统下安装mysql,先下载mysql-community-release-el7-5.noarch.rpm,而后经过yum安装,安装过程一直肯定【Y】便可。

cd /usr/downloads/

wget http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm

rpm -ivh mysql-community-release-el7-5.noarch.rpm

yum install mysql-community-server

安装成功后,重启mysql,并进入mysql数据库,给root用户设置一个密码,密码为“123”。

service mysqld restart

mysql -u root -p

set password for root@localhost = password('123');

openresty链接mysql

lua-resty-mysql模块的官方文档地址: https://github.com/openresty/lua-resty-mysql

lua-resty-mysql - Lua MySQL client driver for ngx_lua based on the cosocket API

lua-resty-mysql模块是基于cosocket API 为ngx_lua提供的一个Lua MySQL客户端。它保证了100%非阻塞。

vim /usr/example/lua/test_mysql.lua,添加如下的代码:

local function close_db(db)  
    if not db then  
        return  
    end  
    db:close()  
end  
  
local mysql = require("resty.mysql")  
 
local db, err = mysql:new()  
if not db then  
    ngx.say("new mysql error : ", err)  
    return  
end  

db:set_timeout(1000)  
  
local props = {  
    host = "127.0.0.1",  
    port = 3306,  
    database = "mysql",  
    user = "root",  
    password = "123"  
}  
  
local res, err, errno, sqlstate = db:connect(props)  
  
if not res then  
   ngx.say("connect to mysql error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)  
   return close_db(db)  
end  
 
local drop_table_sql = "drop table if exists test"  
res, err, errno, sqlstate = db:query(drop_table_sql)  
if not res then  
   ngx.say("drop table error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)  
   return close_db(db)  
end  
  

local create_table_sql = "create table test(id int primary key auto_increment, ch varchar(100))"  
res, err, errno, sqlstate = db:query(create_table_sql)  
if not res then  
   ngx.say("create table error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)  
   return close_db(db)  
end  
  

local insert_sql = "insert into test (ch) values('hello')"  
res, err, errno, sqlstate = db:query(insert_sql)  
if not res then  
   ngx.say("insert error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)  
   return close_db(db)  
end  
  
res, err, errno, sqlstate = db:query(insert_sql)  
  
ngx.say("insert rows : ", res.affected_rows, " , id : ", res.insert_id, "<br/>")  
  
 
local update_sql = "update test set ch = 'hello2' where id =" .. res.insert_id  
res, err, errno, sqlstate = db:query(update_sql)  
if not res then  
   ngx.say("update error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)  
   return close_db(db)  
end  
  
ngx.say("update rows : ", res.affected_rows, "<br/>")  
  
local select_sql = "select id, ch from test"  
res, err, errno, sqlstate = db:query(select_sql)  
if not res then  
   ngx.say("select error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)  
   return close_db(db)  
end  
  
  
for i, row in ipairs(res) do  
   for name, value in pairs(row) do  
     ngx.say("select row ", i, " : ", name, " = ", value, "<br/>")  
   end  
end  
  
ngx.say("<br/>")  
  
local ch_param = ngx.req.get_uri_args()["ch"] or ''  
 
local query_sql = "select id, ch from test where ch = " .. ngx.quote_sql_str(ch_param)  
res, err, errno, sqlstate = db:query(query_sql)  
if not res then  
   ngx.say("select error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)  
   return close_db(db)  
end  
  
for i, row in ipairs(res) do  
   for name, value in pairs(row) do  
     ngx.say("select row ", i, " : ", name, " = ", value, "<br/>")  
   end  
end  
  

local delete_sql = "delete from test"  
res, err, errno, sqlstate = db:query(delete_sql)  
if not res then  
   ngx.say("delete error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)  
   return close_db(db)  
end  
  
ngx.say("delete rows : ", res.affected_rows, "<br/>")  
  
  
close_db(db)

在上面的代码中,展现了基本的创表、插入数据、修改数据、查询数据、删除数据的一些功能。

其中用到的lua-resty-mysql的一些API方法:

  • syntax: db, err = mysql:new() 建立一个mysql数据库链接对象
  • syntax: ok, err = db:connect(options) 尝试远程链接mysql
    • host mysql的主机名
    • port 端口
    • database 数据库名
    • user 用户名
    • password 密码
    • charset 编码
  • syntax: db:set_timeout(time) 设置数据库链接超时时间
  • syntax: ok, err = db:set_keepalive(max_idle_timeout, pool_size) 设置链接池
  • syntax: ok, err = db:close() 关闭数据库
  • syntax: bytes, err = db:send_query(query) 发送查询

lua-resty-mysql的一些关键的API方法,见https://github.com/openresty/lua-resty-mysql#table-of-contents

vim /usr/example/example.conf 在配置文件配置:

location /lua_mysql {
   default_type 'text/html';
   lua_code_cache on;
   content_by_lua_file /usr/example/lua/test_mysql.lua;
 }

浏览器访问http://116.196.177.123/lua_mysql,浏览器显示如下的内容:

insert rows : 1 , id : 2
update rows : 1
select row 1 : ch = hello
select row 1 : id = 1
select row 2 : ch = hello2
select row 2 : id = 2

delete rows : 2

第7篇:模块开发、OpenResty链接Redis

在实际的开发过程当中,不可能把全部的lua代码写在一个lua文件中,一般的作法将特定功能的放在一个lua文件中,即用lua模块开发。在lualib目录下,默认有如下的lua模块。

lualib/
├── cjson.so
├── ngx
│   ├── balancer.lua
│   ├── ocsp.lua
│   ├── re.lua
│   ├── semaphore.lua
│   ├── ssl
│   │   └── session.lua
│   └── ssl.lua
├── rds
│   └── parser.so
├── redis
│   └── parser.so
└── resty
    ├── aes.lua
    ├── core
    │   ├── base64.lua
    │   ├── base.lua
    │   ├── ctx.lua
    │   ├── exit.lua
    │   ├── hash.lua
    │   ├── misc.lua
    │   ├── regex.lua
    │   ├── request.lua
    │   ├── response.lua
    │   ├── shdict.lua
    │   ├── time.lua
    │   ├── uri.lua
    │   ├── var.lua
    │   └── worker.lua
    ├── core.lua
    ├── dns
    │   └── resolver.lua
    ├── limit
    │   ├── conn.lua
    │   ├── req.lua
    │   └── traffic.lua
    ├── lock.lua
    ├── lrucache
    │   └── pureffi.lua
    ├── lrucache.lua
    ├── md5.lua
    ├── memcached.lua
    ├── mysql.lua
    ├── random.lua
    ├── redis.lua
    ├── sha1.lua
    ├── sha224.lua
    ├── sha256.lua
    ├── sha384.lua
    ├── sha512.lua
    ├── sha.lua
    ├── string.lua
    ├── upload.lua
    ├── upstream
    │   └── healthcheck.lua
    └── websocket
        ├── client.lua
        ├── protocol.lua
        └── server.lua

在使用这些模块以前,须要在nginx的配置文件nginx.conf中的http模块加上如下的配置:

lua_package_path "/usr/example/lualib/?.lua;;";  #lua 模块  
 lua_package_cpath "/usr/example/lualib/?.so;;";  #c模块

如今来简单的开发一个lua模块:

vim /usr/example/lualib/module1.lua

在module1.lua文件加上如下的代码:

local count = 0  
local function hello()  
   count = count + 1  
   ngx.say("count : ", count)  
end  
  
local _M = {  
   hello = hello  
}  
  
return _M

开发时将全部数据作成局部变量/局部函数;经过 _M导出要暴露的函数,实现模块化封装。

在/usr/example/lua目录下建立一个test_module_1.lua 文件,在该文件中引用上面的module1.lua文件。

vim /usr/example/lua/test_module_1.lua

加上如下代码:

local module1 = require("module1")  
  
module1.hello()

经过require(“模块名”)来加载模块,若是是多级目录,则须要经过require(“目录1.目录2.模块名”)加载。

在/user/example/example.conf中加上如下的配置:

location /lua_module_1 {  
    default_type 'text/html';  
    lua_code_cache on;  
    content_by_lua_file /usr/example/lua/test_module_1.lua;  
}

屡次在浏览器上访问:http://116.196.177.123/lua_module_1,浏览器显示:

count : 1
count : 2
count : 3

...

安装redis

linux下安装: cd /usr/servers

$ wget http://download.redis.io/releases/redis-3.2.6.tar.gz
$ tar xzf redis-3.2.6.tar.gz
$ cd redis-3.2.6
$ make

启动redis:

nohup /usr/servers/redis-3.2.6/src/redis-server  /usr/servers/redis-3.2.6/redis.conf &

查看是否启动:

ps -ef |grep redis

终端显示:

root     20985 14268  0 18:49 pts/0    00:00:00 /usr/servers/redis-3.2.6/src/redis-server 127.0.0.1:6379

可见redis已经启动。

lua链接redis

lua_resty_redis模块地址:https://github.com/openresty/lua-resty-redis

lua-resty-redis - Lua redis client driver for the ngx_lua based on the cosocket API

lua_resty_redis 它是一个基于cosocket API的为ngx_lua模块提供Lua redis客户端的驱动。

建立一个test_redis_basic.lua文件

vim /usr/example/lua/test_redis_basic.lua

local function close_redis(red)  
    if not red then  
        return  
    end  
  
    local pool_max_idle_time = 10000 --毫秒  
    local pool_size = 100 --链接池大小  
    local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)  
    if not ok then  
        ngx.say("set keepalive error : ", err)  
    end  
end    
  
local redis = require("resty.redis")  
  

local red = redis:new()  
 
red:set_timeout(1000)  

local ip = "127.0.0.1"  
local port = 6379  
local ok, err = red:connect(ip, port)  
if not ok then  
    ngx.say("connect to redis error : ", err)  
    return close_redis(red)  
end  
 
ok, err = red:set("msg", "hello world")  
if not ok then  
    ngx.say("set msg error : ", err)  
    return close_redis(red)  
end  
  

local resp, err = red:get("msg")  
if not resp then  
    ngx.say("get msg error : ", err)  
    return close_redis(red)  
end  

if resp == ngx.null then  
    resp = ''  
end  
ngx.say("msg : ", resp)  
  
close_redis(red)

上面的代码很简单,经过链接池链接Redis,链接上redis后,经过set一对键值对(msg,helloword)到redis中,而后get(msg),并经过ngx.say()返回给浏览器。

vim /usr/example/example.conf,添加如下的配置代码:

location /lua_redis_basic {  
    default_type 'text/html';  
    lua_code_cache on;  
    content_by_lua_file /usr/example/lua/test_redis_basic.lua;  
 }

浏览器访问:http://116.196.177.123/lua_redis_basic

浏览器显示:

msg : hello world

lua_resty_redis支持全部的redis指令,自己Redis就支持lua语言操做。因此lua_resty_redis模块可以提升全部的redis操做的功能。

在不少时候,Redis是设置了口令的,链接时,若是须要验证口令,须要添加 local res, err = red:auth(“foobared”),示例代码以下:

local redis = require "resty.redis"
    local red = redis:new()

    red:set_timeout(1000) -- 1 sec

    local ok, err = red:connect("127.0.0.1", 6379)
    if not ok then
        ngx.say("failed to connect: ", err)
        return
    end

    local res, err = red:auth("foobared")
    if not res then
        ngx.say("failed to authenticate: ", err)
        return
    end

更多请关注的官方文档https://github.com/openresty/lua-resty-redis 和开涛的博客http://jinnianshilongnian.iteye.com/blog/2187328

第8篇:RBAC介绍、sql和redis模块工具类

RBAC(Role-Based Access Control,基于角色的访问控制),用户基于角色的访问权限控制。简单地说,一个用户拥有若干角色,每个角色拥有若干权限。这样,就构形成“用户-角色-权限”的受权模型。在这种模型中,用户与角色之间,角色与权限之间,通常都是多对多的关系。如图所示:

WX20171105-214559@2x.png

sql_tool

在本案例中,采用的就是这种权限设计的方式。具体的sql语句脚本以下:

CREATE TABLE `user` (
`id`  int(11) NOT NULL AUTO_INCREMENT ,
`name`  varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=latin1 COLLATE=latin1_swedish_ci
AUTO_INCREMENT=2
ROW_FORMAT=COMPACT
;


CREATE TABLE role(
`id`  int(11) NOT NULL AUTO_INCREMENT ,
`name`  varchar(255) CHARACTER SET latin5 NULL DEFAULT NULL ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=latin1 COLLATE=latin1_swedish_ci
AUTO_INCREMENT=2
ROW_FORMAT=COMPACT
;

CREATE TABLE permission(
`id`  int(11) NOT NULL AUTO_INCREMENT ,
`permission`  varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=latin1 COLLATE=latin1_swedish_ci
AUTO_INCREMENT=3
ROW_FORMAT=COMPACT
;

CREATE TABLE user_role(
`id`  int(11) NOT NULL AUTO_INCREMENT ,
`user_id`  int(11) NULL DEFAULT NULL ,
`role_id`  int(11) NULL DEFAULT NULL ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=latin1 COLLATE=latin1_swedish_ci
AUTO_INCREMENT=2
ROW_FORMAT=COMPACT
;


CREATE TABLE role_permission(
`id`  int(11) NOT NULL AUTO_INCREMENT ,
`role_id`  int(11) NULL DEFAULT NULL ,
`permission_id`  int(11) NULL DEFAULT NULL ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=latin1 COLLATE=latin1_swedish_ci
AUTO_INCREMENT=3
ROW_FORMAT=COMPACT
;

初始化如下的sql脚本,即给用户id为1的用户关联角色,角色并关联权限:

INSERT INTO `permission` VALUES ('1', '/user/orgs');
INSERT INTO `role` VALUES ('1', 'user');
INSERT INTO `role_permission` VALUES ('1', '1', '1');
INSERT INTO `user` VALUES ('1', 'forezp');
INSERT INTO `user_role` VALUES ('1', '1', '1');

在本案例中,须要根据user表中的Id获取该Id对应的权限。首先根据userId获取该用户对应的角色,再根据根据该角色获取相应的权限,每每一个用户具备多个角色,而角色又有多个权限。好比查询userId为1 的用户的权限的sql语句以下:

SELECT  a.id,a.permission from permission a ,role_permission b,role c,user_role d,user e WHERE a.id=b.permission_id and c.id=b.role_id and d.role_id=c.id and d.user_id=e.id and e.id=1"

在Openresty中怎么链接数据库,怎么查询sql语句,在以前的文章已将讲述过了。根据用户id获取用户的权限的功能是一个使用率极高的功能,因此考虑将这个功能模块化。

vim /usr/example/lualib/sql_tool.lua ,编辑加入如下的代码:

local mysql = require("resty.mysql")  
 
local function close_db(db)  
    if not db then  
        return  
    end  
    db:close()  
end  

local function select_user_permission(user_id)

   local db, err = mysql:new()
   if not db then  
      ngx.say("new mysql error : ", err)  
      return  
   end 
   db:set_timeout(1000)  
  
   local props = {  
      host = "127.0.0.1",  
      port = 3306,  
      database = "test",  
      user = "root",  
      password = "123"  
   }

  local res, err, errno, sqlstate = db:connect(props)  
  
  if not res then  
     ngx.say("connect to mysql error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)  
     close_db(db)
  end
  
  local select_sql = "SELECT  a.id,a.permission from permission a ,role_permission b,role c,user_role d,user e WHERE a.id=b.permission_id and c.id=b.role_id and d.role_id=c.id and d.user_id=e.id and e.id="..user_id
  res, err, errno, sqlstate = db:query(select_sql)  
  if not res then  
     ngx.say("select error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)  
     return close_db(db)  
  end  

   local permissions={}
   for i, row in ipairs(res) do  
     for name, value in pairs(row) do
    if name == "permission" then
          table.insert(permissions, 1, value)
        end  
 
     end  
   end  
 return permissions 
end

local _M = {  
    select_user_permission= select_user_permission
}  
  
return _M

在上面的代码中,有一个select_user_permission(user_id)方法,该方法根据用户名获取该用户的权限。查出来存在一个table 类型的 local permissions={}中。

vim /usr/example/example.conf 加上如下的代码:

location ~ /sql_tool{
  default_type 'text/html';
  content_by_lua_file /usr/example/lua/test_sql_tool.lua;
 }

在浏览器上访问http://116.196.177.123/sql_tool,浏览器显示以下的内容:

/user/orgs

tokentool

在以前的文章讲述了如何使用Openresty链接redis,并操做redis。 这小节将讲述如何使用openresty链接redis,并写几个方法,用于存储用户的token等,并将这些信息模块化,主要有如下几个方法:

  • close_redis(red) 经过链接池的方式释放一个链接
  • connect() 链接redis
  • has_token(token) redis中存在token 与否
  • get_user_id(token) 根据token获取用户id
  • set_permissions(user_id,permissions) 根据userid设置权限
  • get_permissions(user_id)根据userid获取权限

vim /usr/example/lualib/tokentool.lua 编辑一下内容:

module("tokentool", package.seeall)
local redis = require "resty.redis"
local str = require "resty.string"
local cjson = require("cjson")  


local redis_host = "127.0.0.1"
local redis_port = 6379

local function close_redis(red)  
    if not red then  
        return  
    end  
    local pool_max_idle_time = 10000 --毫秒  
    local pool_size = 100 --链接池大小  
    local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)  
    if not ok then  
        ngx.say("set keepalive error : ", err)  
    end  
end 

local function connect()
    local red = redis:new()
    red:set_timeout(1000)
    local ok, err = red:connect(redis_host, redis_port)
    if not ok then
        return false
    end
    --local res, err = red:auth("xiaoantimes")
    --if not res then
     -- ngx.say("failed to authenticate: ", err)
     -- return false
    --end
    --ok, err = red:select(1)
    --if not ok then
      --  return false
    --end
    return red
end

function has_token(token)
    local red = connect()
    if red == false then
        return false
    end

    local res, err = red:get(token)
    if not res then
        return false
    end
    close_redis(red)  
    return true
end

function set_permissions(user_id,permissions)
  if (permissions==null) or( permissions==ngx.null) then
     return false
  end 
  local str = cjson.encode(permissions)  
  ngx.log(ngx.ERR,"set redis p:"..str)
  local red=connect()
  if red== false then
     return false
  end
  local ok, err = red:set(user_id,str)
  if not ok then
     return false
  end
  return true 
end

function get_permissions(user_id)
  local red=connect()
  if red== false then
     return false
  end
  local res, err = red:get(user_id)
  if (not res) or (res == ngx.null) then
     return
  end 
  ngx.log(ngx.ERR,"get redis p:"..res);
  local permissions=cjson.decode(res)  
  return permissions
end

function get_user_id(token)
    local red = connect()
    local resp, err = red:get(token)  
    if not resp then  
      ngx.say("get msg error : ", err)  
      return close_redis(red)  
    end  
    close_redis(red)  
    return resp
end

vim /usr/example/lua/test_token_tool.lua,加上如下的内容:

local tokentool= require "tokentool"
local ret = tokentool.has_token("msg")
ngx.log(ngx.ERR,ret)
if ret == true then
   ngx.say("ok")
else
   ngx.say("oops,error")
end

在/usr/example/example.conf加上如下的内容:

location ~ /token_tool{
     default_type 'text/html';
     lua_code_cache on;
     content_by_lua_file /usr/example/lua/test_token_tool.lua;

 }

打开浏览器访问http://116.196.177.123/token_tool,浏览器显示:

ok

第9篇:Openresty实现的网关权限控制

采用openresty 开发出的api网关有不少,好比比较流行的kong、orange等。这些API 网关经过提供插件的形式,提供了很是多的功能。这些组件化的功能每每可以知足大部分的需求,若是要想达到特定场景的需求,可能须要二次开发,好比RBAC权限系统。本小节经过整合前面的知识点,来构建一个RBAC权限认证系统。

技术栈

本小节采用了如下的技术栈:

  • Openresty(lua+nginx)
  • mysql
  • redis
  • cjson

验证流程

  • 用户请求通过nginx,nginx的openresty的模块经过拦截请求来进行权限判断
  • openresty的access_by_lua_file模块,进行了一系列的判断
    • 用户的请求是否为白名单uri,若是为白名单uri,则直接经过验证,进入下一个验证环节content_by_lua_file,这个环节直接打印一句话:“恭喜,请求经过。”
    • 若是用户请求不为白名单url,则须要取出请求header中的token,若是请求的header不存在token,则直接返回结果401,无权限访问。
    • 若是用户请求的uri的请求头包含token ,则取出token,解密token取出用户id
    • 根据取出的userid去查询数据库获取该用户的权限,若是权限包含了该请求的uri,请求能够经过,不然,请求不经过。
  • 请求若是经过access_by_lua_file模块,则进入到content_by_lua_file模块,该模块直接返回一个字符串给用户请求,在实际的开发中,可能为路由到具体的应用程序的服务器。

验证流程图以下所示:

WX20171106-114542@2x.png

vim /usr/example/example.conf ,加上如下的配置:

location / {
    default_type "text/html";
    access_by_lua_file /usr/example/lua/api_access.lua;
    content_by_lua_file /usr/example/lua/api_content.lua;
  }

以上的配置表示,要不符合已有location路径的全部请求,将走这个location为/ 的路径。符合这个location的请求将进入 access_by_lua_file和 content_by_lua_file的模块判断。

vim /usr/example/lua/access_by_lua_file ,加上如下代码:

local tokentool = require "tokentool"
local mysqltool = require "mysqltool"

 function is_include(value, tab)
   for k,v in ipairs(tab) do
      if v == value then
           return true
       end
    end
    return false
 end

local white_uri={"/user/login","/user/validate"}
  
--local user_id = ngx.req.get_uri_args()["userId"]
--获取header的token值
local headers = ngx.req.get_headers() 
local token=headers["token"]
local url=ngx.var.uri
if ( not token) or (token==null) or (token ==ngx.null) then
  if is_include(url,white_uri)then
     
  else
    return ngx.exit(401)
  end  
else 
  ngx.log(ngx.ERR,"token:"..token)
  local user_id=tokentool.get_user_id(token)
  if (not user_id) or( user_id ==null) or ( user_id == ngx.null) then
      return ngx.exit(401)   
  end 
  
  ngx.log(ngx.ERR,"user_id"..user_id)
  local permissions={}
  permissions =tokentool.get_permissions(user_id)
  if(not permissions)or(permissions==null)or( permissions ==ngx.null) then
      permissions= mysqltool.select_user_permission(user_id)
      if permissions and permissions ~= ngx.null then
         tokentool.set_permissions(user_id,permissions)
      end
  end  
  if(not permissions)or(permissions==null)or( permissions ==ngx.null) then
     return ngx.exit(401)
  end 
  local is_contain_permission = is_include(url,permissions) 

  if is_contain_permission == true  then
     -- ngx.say("congratuation! you have pass the api gateway")
  else
      return ngx.exit(401) 
  end   
end

在上述代码中:

  • is_include(value, tab),该方法判断某个字符串在不在这个table中。
  • white_uri={“/user/login”,”/user/validate”} 是一个白名单的列表。
  • local headers = ngx.req.get_headers()从请求的uri的请求头获取token
  • is_include(url,white_uri)判断该url是否为白名单url
  • local user_id=tokentool.get_user_id(token)根据token获取该token对应的用户的user_id,在常见状况下,是根据token解析出user_id,但在不一样的语言加密和加密token存在盐值不同的状况,比较麻烦,因此我偷了个懒,直接存了redis,用户登陆成功后存一下。
  • permissions =tokentool.get_permissions(user_id)根据user_id 从redis获取该用户的权限。
  • permissions= mysqltool.select_user_permission(user_id)若是redis没有存该用户的权限,则从数据库读。
  • tokentool.set_permissions(user_id,permissions),将从数据库中读取的权限点存在reddis中。
  • local is_contain_permission = is_include(url,permissions),判断该url 在不在该用户对应的权限列表中。

若是全部的判断经过,则该用户请求的具备权限访问,则进入content_by_lua_file模块,直接在这个模块给请求返回“congratulations! you have passed the api gateway”。

vim /usr/example/lua/api_content.lua ,添加如下内容:

ngx.say("congratulations!"," you have passed ","the api gateway")  
----200状态码退出  
return ngx.exit(200)

验证演示

打开浏览器访问http://116.196.177.123/user/login,浏览器显示:

congratulations! you have passed the api gateway

/user/login这个url 在白名单的范围内,因此它是能够经过权限验证的。

打开浏览器访问http://116.196.177.123/user/sss,显示如下内容:

401 Authorization Required

openresty/1.11.2.4

在redis中添加一对key-value,key为token_forezp,value为1,即token_forezp对应的用户的id为1.

/usr/servers/redis-3.2.6

src/redis-cli

set token_forezp 1

初始化如下的sql脚本,即给用户id为1的用户关联角色,角色并关联权限:

INSERT INTO `permission` VALUES ('1', '/user/orgs');
INSERT INTO `role` VALUES ('1', 'user');
INSERT INTO `role_permission` VALUES ('1', '1', '1');
INSERT INTO `user` VALUES ('1', 'forezp');
INSERT INTO `user_role` VALUES ('1', '1', '1');

用postman请求,在请求头中加入token,值为token_forezp,请求结果以下:

WX20171104-182432@2x.png

相关文章
相关标签/搜索