openresty的简单使用,openresty简单使用


Openresty: Nginx核心加很多第三方模块组成,默认集成lua开发环境,提供了大量组件如Mysql、Redis、Memcached等等

安装

1)步骤

#!/bin/bash

tar xvf openresty-1.9.7.3.tar.gz

cd openresty-1.9.7.3

./configure --with-luajit --with-http_drizzle_module --with-http_iconv_module --with-ld-opt="-Wl,-rpath,/usr/local/lib"  --with-http_stub_status_module --with-http_ssl_module --with-http_sub_module

gmake

gmake install

--with-luajit              集成luajit模块

2)安装结果

Luajitluajit环境lua是一种解释语言,通过luajit可以即时编译lua代码到机器代码,得到很好的性能

Lualib要使用的lua库,里边提供了一些默认的lua库,如redis,json库等,也可以把一些自己开发的或第三方放在这

Config:存放nginx配置文件。

(3)配置环境

a.配置配置文件路径

http{}块中添加如下内容:

include     /usr/local/openresty/config/*.conf;

所有的配置文件存放在/usr/local/openresty/config/目录下。

b.另外,如果在测试环境中,为了在修改完lua代码之后立即生效,不需要执行nginx -s reload,可以在http{}块中添加lua_code_cache off;默认开启,表示缓存lua代码。

3nginx+lua开发

1)流程:

a).接收请求

nginx配置文件

/usr/local/openresty/config/目录下创建xxx.conf文件,名字随意。

hello.conf

server {

   listen 80;

   server_name        xxx.xxx.xxx.xxx;

   access_log          /var/log/hello_access_80.log  main;

   location /hello {

     default_type "text/html";

     #接收到请求后,hello.lua做处理

     content_by_lua_file /usr/local/openresty/lua/hello.lua;

   }

}

对外提供的接口为http://xxx.xxx.xxx.xxx/hello

b).处理请求

hello.lua

local uri_args = ngx.req.get_uri_args()

for k, v in pairs(uri_args) do

  ngx.say(k, ": ", v, "<br/>")

end

ngx.say("hello")

表示获取请求参数。以k:v方式输出。

c).获取响应

浏览器:http://xxx.xxx.xxx.xxx/hello?instance=100&params=test

params: test
instance: 100
hello

(2)常用API

1、基础API

a).ngx.var: nginx变量

案例:

nginx配置文件:

location /var {

   default_type "text/html";

   set $a 1;

   set $b 2;

   content_by_lua_file /data/local/openresty/lua/var.lua;

}

lua文件:

local var = ngx.var

ngx.say("ngx.var.a: "..var.a.."<br/>")

ngx.say("ngx.var.b: "..var.b.."<br/>")

ngx.say("ngx.var.uri: "..var.uri.."<br/>")   

ngx.say("ngx.var.remoteip: ".. ngx.var.remote_addr)    

ngx.var.uri获取location后的值。

ngx.var.remote_addr获取客户端ip

b).ngx.req.get_method():获取请求类型

获取POSTGET等请求类型。

 

c).ngx.req.get_uri_args():获取url请求参数

适用于get请求的请求参数。参考上面的案例。

 

d).ngx.req.get_post_args():获取post请求内容体

在之前需要调用ngx.req.read_body()读取body体。

案例:

ngx.req.read_body()

local uri_args = ngx.req.get_post_args()

ngx.say(uri_args.method)

但采用postman发送请求,该方法无法获取到postman的参数,适用于表单以及js发送ajax请求。

e).ngx.req.get_body_data():获取post请求参数

cjson = require("cjson")

ngx.req.read_body()

local uri_args = ngx.req.get_body_data()

uri_args = cjson.decode(uri_args)

ngx.say(uri_args.method)

若通过postman发送post请求,获取到的参数是未解析的请求body体内容字符串采用该方法获取参数。

f).ngx.say()ngx.print():输出响应

ngx.say("hello")      --表示输出hello/r/n

ngx.print("hello")     --表示输出hello

 

3nginx+lua全局内存

nginx是一个Master进程多个Worker进程的工作方式,因此我们可能需要在多个Worker进程中共享数据,那么此时就可以使用ngx.shared.DICT来实现全局内存共享。

1)在nginx.conf文件中分配内存大小

lua_shared_dict shared_data 10m

2nginx路由配置

   location /dict {

     default_type "text/html";

     content_by_lua_file /usr/local/openresty/lua/dict.lua;

   }

(2)lua代码

a).案例1

--获取共享内存变量

local shared_data = ngx.shared.shared_data

--获取字典值

local port = shared_data:get("port")

if not port then

  ngx.say("port is null ")

  --设置字典值

  shared_data:set("port", "3306")

end

--重新获取字典值

local port_new = shared_data:get("port")

ngx.say("port_new: "..port_new)

b).案例2

local shared_data = ngx.shared.shared_data

--删除字典

shared_data:delete("port")

--获取字典

local port = shared_data:get("port")

if not port then

  ngx.say("port is null <br/>")

end

4nginx+lua访问控制模块

nginx11个处理阶段,而相应的处理阶段是可以做插入式处理,即可插拔式架构;另外指令可以在httpserverserver iflocationlocation if几个范围进行配置:

1init_by_luainit_by_lua_file

使用范围:http

阶段:    loading-config

nginx master 进程在加载 nginx 配置文件时运行指定的 lua 脚本,通常用来注册 lua 的全局变量或在服务器启动时预加载 lua 模块

案例1:

a).nginx.conf(在http{}块中)

init_by_lua 'cjson = require "cjson"';

b).配置文件

   location /init {

     default_type "text/html";

     content_by_lua 'ngx.say(cjson.encode({dog = 5, cat = 6}))';

   }

案例2:

a).nginx.conf(在http{}块中)

init_by_lua '

local shared_data = ngx.shared.shared_data;

shared_data:set("test",50)

';

b).配置文件

   location /test {

     default_type "text/html";

     content_by_lua '

local shared_data = ngx.shared.shared_data;

ngx.say(shared_data:get("test"))

';

   }

不要在这个阶段初始化你的私有lua全局变量,因为使用lua全局变量会照成性能损失,并且可能导致全局命名空间被污染。

 

2init_worker_by_luainit_worker_by_lua_file

使用范围:http

阶段:starting-worker

这个hook通常用来创建每个工作进程的计时器(通过luangx.timer API),进行后端健康检查或者其它日常工作

 

3set_by_luaset_by_lua_file

使用范围:serverserver iflocationlocation if

阶段:rewrite

设置一个变量,常用与计算一个逻辑,然后返回结果 该阶段不能运行Output APIControl APISubrequest APICosocket API

Output API: ngx.sayngx.send_headers

Control API: ngx.exit

Subrequest API: ngx.location.capturengx.location.capture_multi

Cosocket API: ngx.sleep

这个指令是为了执行短期、快速运行的代码因为运行过程中nginx的事件处理循环是处于阻塞状态的。耗费时间的代码应该被避免。

案例:

a).配置文件

   location /set {

     default_type "text/html";

     set $diff '';

     set_by_lua_file $num /usr/local/openresty/lua/set.lua;

     echo "sum = $num, diff = $diff";

   }

b).lua代码

local a = 32

local b = 56

ngx.var.diff = a - b;

return a + b;

set_by_lua_file运行Nginx外部的lua脚本,能够避免在配置文件里使用大量的转义。

4rewrite_by_luarewrite_by_lua_file

实现url重写。在rewrite阶段运行。

a).配置文件

   location /rewrite {

     default_type "text/html";

     rewrite_by_lua_file /data/local/openresty/lua/rewrite.lua;

     echo 'in rewrite';

   }

   location =/other {

     default_type "text/html";

     echo 'in other';

   }

b).lua代码

rewrite.lua代码

ngx.exec("/other")

此时发送请求http://xxx.xxx.xxx.xxx/rewrite,由于locationrewrite改写了,所以请求结果为in other

5access_by_luaaccess_by_lua_file

执行在access阶段。用于訪问控制。

a).配置文件

   location /access {

     default_type "text/html";

     access_by_lua_file /data/local/openresty/lua/access.lua;

     echo "welcome";

   }

b).lua代码

if ngx.var.arg_user == "ntes" then

  return

else

  ngx.exit(ngx.HTTP_FORBIDDEN)

end

当访问http://xxx.xxx.xxx.xxx/access?user=ntes,输出welcome

当访问http://xxx.xxx.xxx.xxx/access?user=test,输出403Forbidden

6content_by_luacontent_by_lua_file

content阶段运行,生成http响应。因为content阶段仅仅能有一个handler。所以在与echo模块使用时,不能同一时候生效,我测试,添加echo后,只输出echo后的结果。

查看上面的案例。

7ngx.location.capture

用于发出一个同步的,非堵塞的Nginxsubrequest(子请求)。

a).配置文件

   location =/other {

     default_type "text/html";

     echo 'in other';

   }

   location /capture {

     default_type "text/html";

     content_by_lua_file /data/local/openresty/lua/capture.lua;

   }

b).lua代码

local res = ngx.location.capture("/other")

if res.status == 200 then

  ngx.print(res.body)

end

8ngx.location.capture_multi

并行的、非堵塞的发出多个子请求

a).配置文件

   location /son {

     default_type "text/html";

     echo "in son";

   }

   location /daughter {

     default_type "text/html";

     echo "in daughter";

   }

 

   location /multi {

     default_type "text/html";

     content_by_lua_file /data/local/openresty/lua/multi.lua;

   }

b).lua代码

local res1,res2 = ngx.location.capture_multi({{"/son"}, {"/daughter"}})

if res1.status == 200 then

  ngx.say(res1.body)

end

if res2.status == 200 then

  ngx.say(res2.body)

end

ngx.location.capture_multi并行的、非堵塞的发出多个子请求。这种方法在全部子请求处理完毕后返回。而且整个方法的执行时间取决于执行时间最长的子请求,并非全部子请求的执行时间之和。

Lua代码中的网络IO操作仅仅能通过Nginx Lua API完毕。假设通过标准Lua API会导致Nginx的事件循环被堵塞,这样性能会急剧下降。在进行数据量相当小的磁盘IO时能够採用标准Lua io库,可是当读写大文件时这样是不行的,由于会堵塞整个NginxWorker进程。为了获得更大的性能。强烈建议将全部的网络IO和磁盘IO托付给Nginx子请求完毕(通过ngx.location.capture)。

5nginx+lua web网页开发(模板渲染)

1)下载template.lua

进入/usr/local/openresty/lualib/resty目录,下载template.lua

wget https://raw.githubusercontent.com/bungle/lua-resty-template/master/lib/resty/template.lua

2)配置模板位置

server{}中添加   

set $template_location "/template";

set $template_root "/usr/local/openresty/template/";

3nginx配置

   location /template {

     default_type "text/html";

     content_by_lua_file /usr/local/openresty/lua/template.lua;

   }

4lua代码(template.lua

local template = require "resty.template"

  

local context = {  

    title = "测试",  

    name = "张三",  

    description = "成绩统计",  

    age = 20,  

    hobby = {"电影", "音乐", "阅读"},  

    score = {语文 = 90, 数学 = 80, 英语 = 70},  

    score2 = {  

        {name = "语文", score = 90},  

        {name = "数学", score = 80},  

        {name = "英语", score = 70},  

    }  

}    

template.render("template.html", context)

7html代码(template.html

<!DOCTYPE html>

<html>

   <head>

     <meta charset="utf-8" />

     <meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />

   </head>

   <body>  

      {# 不转义变量输出 #}  

      姓名:{* string.upper(name) *}

      <br/>  

      {# 转义变量输出 #}  

      简介:{{description}}

      <br/>  

      {# 可以做一些运算 #}  

      年龄: {* age + 1 *}

      <br/>  

      {# 循环输出 #}  

      爱好:  

      {% for i, v in ipairs(hobby) do %}  

         {* v *}  

      {% end %}

      <br/>  

  

      成绩:  

      {% local i = 1; %}  

      {% for k, v in pairs(score) do %}  

         {* k *} = {* v *}  

         {% i = i + 1 %}  

      {% end %}

      <br/>  

      成绩2:  

      {% for i = 1, #score2 do local t = score2[i] %}  

          {* t.name *} = {* t.score *}  

      {% end %}

      <br/>  

      {# 中间内容不解析 #}  

   </body>

</html>

8)访问http://xxx.xxx.xxx.xxx/template

可以随意改变lua中的值去渲染页面。




PS

下方是我个人订阅号,会一直更新各类技术文章,欢迎关注  :)






相关内容

    暂无相关文章