急需:依据客户要求,能够在ngx下
通过lua做接口一遍封装再度转载给用户或第3方

windows下openresty中采用lua做接口转载、二回封装等,openrestylua

急需:根据客户必要,能够在ngx下
通过lua做接口二回封装再一次转载给用户或第一方

场景:对重回值有供给的、接口屏蔽字段、或做壹些政工上的证实等

windows下openresty中动用lua做接口转载,用openResty做二个小功能。一、windows直接下载openresty 解压即可,就马到功成了windows下使用lua的开发条件

2、配置:

a、在nginx.conf里http下配置如下代码:

include       mime.types;
default_type  application/octet-stream;
lua_package_path "/lualib/?.lua;;";  #lua 模块  
lua_package_cpath "/lualib/?.so;;";  #c模块   
include lua.conf;   #导入自定义lua配置文件
resolver 8.8.8.8;

b、在nginx.conf同目录创设lua.conf文件尤其存放lua的路由配置

#lua.conf  
server {  
 charset utf-8; #设置编码
    listen       80;  
    server_name  _;  
 location /user {  
  default_type 'text/html';  
  content_by_lua_file lua/api/userController.lua; #相对于nginx安装目录  
 } 
}    

c、在ngx根目录下的lua文件夹里成立“api”文件夹,并且在内部添加userController.lua
处理文件类,例如代码如下:

local request_method = ngx.var.request_method
local args = nil

--1、获取参数的值 获取前端提交参数
if "GET" == request_method then
    args = ngx.req.get_uri_args()
elseif "POST" == request_method then
    ngx.req.read_body()
    args = ngx.req.get_post_args()
end

--2、组合url请求Get/Post请求 并获取参数  
local http = require "resty.http"  
local httpc = http.new()  
local url = "http://xxxxx/user/login/"..args["userid"].."/"..args["pass"]
local resStr --响应结果  
local res, err = httpc:request_uri(url, {  
    method = "GET",  
    --args = str,  
     body = "a=1&b=2",
    headers = {  
       ["Content-Type"] = "application/json",  
    }  
})  

--3、开始重新组合参数 例子 可根据返回的JSON自己处理
local cjson = require "cjson"
local sampleJson = [[{"age":"23","testArray":{"array":[8,9,11,14,25]},"Himi":"himigame.com"}]];
--解析json字符串
local data = cjson.decode(sampleJson);
--打印json字符串中的age字段
ngx.say(data["age"]);
--打印数组中的第一个值(lua默认是从0开始计数)
ngx.say(data["testArray"]["array"][1]);  


--4、打印输出新返回值
ngx.say(res.body) 

三、运维ngx服务器,访问地址,路由为user  

 

需要:依据客户要求,可以在ngx下
通过lua做接口三回封装再一次转载给用户或第…

须要:依据客户供给,能够在ngx下
通过lua做接口二回封装再次转载给用户或第二方

导读:demo都以在自笔者本地一个域名下做到的。可是文中分了。m.yanshinian.com,api.yanshinian.com,shopapi.yanshinian.com。别搞晕了。
文中涉及到openResty、vue、laravel、lua、nginx缓存、本地dns配置的选取。都以总结的施用。

意况:对再次回到值有要求的、接口屏蔽字段、或做一些作业上的注解等

此情此景:对重返值有供给的、接口屏蔽字段、或做1些政工上的表明等

数码替换

何以选拔openResty呢?

咱俩早就有恢宏页面使用了静态数据。开发动态接口,要合作从前的数码(比如说:在此之前目录在a目录下边,小编通过更换链接,用location匹配,依旧去拿a目录上面包车型地铁静态数据处理),并且上线热切。

openResty的好处就绝不说了。上边包车型客车文章是本身遵照实际工作,编了1个demo(原理一样)。

一、windows直接下载openresty 解压即可,就实现了windows下使用lua的付出环境

一、windows间接下载openresty 解压即可,就成功了windows下使用lua的支付环境

叙述下业务场景

用作一个运转后台跟超级市场后台是分手的两套系统。有一天产品经营说,大家要博取商城的数据变动商品静态页呈现。那么在营业后台供给创制一张商品表用来保存从超级市场接口的取得的货物数量。于是小明化解了,后台湾学生成json文件作为数据源。前台通过VUE去渲染。

有1天产品经营,过来说,原来的纯静态不满意了。比如我要显得库存,要做成动态的。于是,小明用openResty做动态的显得。

2、配置:

2、配置:

达成思路

  1. 获取json文件

贰.获得拥有商品的id

叁.用id数组请求接口,获得数量

4.做多少替换并出口

相关demo编写

a、在nginx.conf里http下配置如下代码:

a、在nginx.conf里http下配置如下代码:

选用lua要小心的题材

壹.lua文书路径

先后中引进了第2方的模块。记得设置文件查找路径。比如,作者利用了第二方的http请求库——lua-resty-http。即便未有安装路径。那么会报如下错误,它会从私下认可的路径去找。

no file '/usr/local/openresty/site/lualib/resty/http.lua'

no file '/usr/local/openresty/site/lualib/resty/http/init.lua'

no file '/usr/local/openresty/lualib/resty/http.lua'

no file '/usr/local/openresty/lualib/resty/http/init.lua'

no file '/usr/local/openresty/site/lualib/resty/http.so'

no file '/usr/local/openresty/lualib/resty/http.so'

no file '/usr/local/openresty/site/lualib/resty.so'

no file '/usr/local/openresty/lualib/resty.so'

no file '/usr/local/openresty/site/lualib/resty/http.lua'

no file '/usr/local/openresty/site/lualib/resty/http/init.lua'

no file '/usr/local/openresty/lualib/resty/http.lua'

能从错误中看出来会去安装后openresty目录中找。/usr/local/openresty/site/lualib/
和’/usr/local/openresty/lualib/

就此要去nginx.conf配置文件中,在http模块里面去设置如下

lua_package_path "/usr/local/openresty/lualib/?.lua;/usr/local/openresty/lualib/lua-resty-http/lib/?.lua    ;;"; #文件查找路径

lua_package_cpath "/usr/local/openresty/lualib/?.so;;"; # 模块路径

看了上边的布署了吗。大家把lua-resty-http第叁方库放到了。openresty/lualib上面了。当然你能够停放项目底下。配置好对应路径也是足以的。

2.location 中 content_by_lua_file (放在它上边)此前需求设置
dns的解析,假如做了内网的限量,那么找个内网的DNS地址(安装配备Dnsmasq
)即可,设置如下

resolver 114.114.114.114  8.8.8.8; #针对外网
include       mime.types;
default_type  application/octet-stream;
lua_package_path "/lualib/?.lua;;";  #lua 模块  
lua_package_cpath "/lualib/?.so;;";  #c模块   
include lua.conf;   #导入自定义lua配置文件
resolver 8.8.8.8;
include       mime.types;
default_type  application/octet-stream;
lua_package_path "/lualib/?.lua;;";  #lua 模块  
lua_package_cpath "/lualib/?.so;;";  #c模块   
include lua.conf;   #导入自定义lua配置文件
resolver 8.8.8.8;

千帆竞发开发吧

关联到的学识:laravel框架、vue、luajit、openresty、一张简略的商品表

壹.预备数据

商品表如下

CREATE TABLE  `yan_product` (
    `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
    `product_id` BIGINT(20) NOT NULL DEFAULT '0' COMMENT '商品ID',
    `title` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '商品标题',
    `img` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '商品图片',
    `price` FLOAT NOT NULL DEFAULT '0' COMMENT '商品价格',
    `sales_num` INT(11) NOT NULL DEFAULT '0' COMMENT '销量',
    `stock_num` INT(11) NOT NULL DEFAULT '0' COMMENT '库存数量',
    PRIMARY KEY (`id`),
    INDEX `idx_product_id` (`product_id`)
)
COMMENT='商品表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=5
;

无论在Tmall里面随便找了个商品,借用下不难的多少。(假装那条数据是从事商业城api调用过来的)

INSERT INTO `yan_product` (`product_id`, `title`, `img`, `price`, `sales_num`, `stock_num`) VALUES (542456857815, '甜而不腻回味无穷', 'gju1.alicdn.com/tps/i4/1130806076898038137/TB2nkXyzItnpuFjSZFvXXbcTpXa_!!6000000001308-0-jupush.jpg_360x360Q50.jpg', 28.8, 120, 122);

2.准备php代码

laravel框架成立叁个控制器(比如叫做ProductController),写3个生成json的先后,如下:

class ProductController extends Controller
{
    public function buildjson()
    {
        $productList = DB::select('select * from yan_product');
        $json = json_encode([
            'productList' => $productList,
        ]);
        $dir = public_path() . '/product' ;
        if (!file_exists($dir)) {
            mkdir($dir, 0777);
        }
        $path = $dir . '/product.json';
        File::put($path, 'callBack(' . $json . ')');
    }
}

地点代码就是,把json保存到了,public文件夹下边,具体路径为
public/product/product.json (product文件特别存放商品的json)。后面拼接
callBack 是jsonp跨域请求格局。要是大家接口域名是api.yanshinian.com
前台域名是m.yanshinian.com。那么m.yanshinian.com 请求api 网址(链接为
api.yanshinian.com),会涉及到跨域的难题。

安排路由

Route::Any('product/buildjson', ['as' => 'product.buildjson', 'uses' => 'App\Modules\Product\Controllers\ProductController@buildjson']);

接下来实施 buildjson,在public/product 目录下生成2个product.json 文件

三.预备前台的页面。使用vue代码

引进相应的 js文件

https://unpkg.com/vue@2.1.10/dist/vue.js

https://cdn.jsdelivr.net/npm/vue-resource@1.3.4

驷马难追代码如下:

相当粗劣的html

<div id="app">

    <ul>
        <li v-for="product in productList">
            <p>productId: {{product.product_id}}</p>
            <p>title: {{product.title}}</p>
            <p>img: {{product.img}}</p>
        </li>
    </ul>
</div>

相当粗劣的vue

var app = new Vue({
        el: '#app',
        mounted: function() {
            alert('加载中....');
            this.$http.jsonp('http://api.yanshinian.com/product/product.json',{
                jsonp:'callback',
                jsonpCallback: 'callback'
            }).then(function(res) {
                console.log(this.productList)
                  this.productList = JSON.parse(res.bodyText).productList
                  console.log(this.productList)

            }) 
        },
        data: {
            productList: ''
        },
        methods: {
            getProductList: function() {
                alert(23);
            }
        }
 });

jsonp请求到数码,并且渲染出来了。糙图如下:

澳门金沙国际 1

商品列表.png

澳门金沙国际,唯独,它是纯静态的。接下来大家初阶用lua替换静态页面。变成动态的数据。

4.假装开发3个杂货店的接口(下一步会用lua脚本调用)。

public function getProductList(Request $request)
{
    $ids = trim($request->input('ids'),',');
    $productList = DB::select('select product_id, stock_num from yan_product where product_id in (' . $ids . ')');
    $data = [];
    foreach ($productList as $v) {
        $data[$v->product_id]= [
            'stock_num'=>$v->stock_num
        ];
    }
    return $data;
}

安排路由

Route::Any('product/productlist', ['as' => 'product.productlist', 'uses' => 'App\Modules\Product\Controllers\ProductController@getProductList']);

post请求,参数ids = ‘542456857815,542456857817’(ids 是product_id)

{"542456857815":{"stock_num":234},"542456857817":{"stock_num":122}}

5.布局location,用lua去过滤2遍

location /product/filter/product.json  { 
    resolver 127.0.0.1; 
    content_by_lua_file /home/nobody/lua/product.lua; #路径自己随意
}

那边有个注意事项正是resolver,须要安顿当地的dns解析。安装Dnsmasq并配备(参考链接:《Dnsmasq安装与配置》http://www.360doc.com/content/14/0913/13/8314158\_409140713.shtml)
,在自己布置的历程中,没安排对外网的解析,导致了git代码不能够交付(报错如下ssh:
Could not resolve hostname git.xxxx.org: Name or service not
known,须求这么弄下,echo ‘nameserver 八.八.八.8’ >
/etc/resolv.dnsmasq.conf)

  1. lua代码 如下

local json = require "cjson"
-- 获取 body内容
-- local bodyJson = ngx.arg[1] -- 这条语句是我觉得body_filter 阶段可以过滤,但事实上,不能发送http请求。所以还是选择在content_by_lua_file 阶段处理

local productListRes = ngx.location.capture("/product/product.json") -- 子查询
local bodyJson = productListRes.body
-- cjson解析
local data = json.decode(string.sub(bodyJson,10,-2))


-- 获取ids
local ids = "";
-- ngx.log(ngx.ERR, json.encode(data));
for k,v in pairs(data.productList) do
    ids = ids..v.product_id..','
end
-- 发送http请求,拿到数据
local http = require "resty.http"

    local httpc = http.new()
function http_request(method, url, param_str)
    local res, err = httpc:request_uri(url, {
        method = method,
        body = param_str,
        headers = {
            ["Content-Type"] = "application/x-www-form-urlencoded",
        },
        ssl_verify = false,
    })

    if not res then
        ngx.log(ngx.ERR, "failed to request: "..err)
        return false;
    end
    return res;
end

local url = "http://shopapi.yanshinian.com/product/productlist"

local res = http_request("POST", url, "ids="..ids)

local productList = json.decode(res.body)
ngx.log(ngx.ERR, json.encode(productList));
-- 解析数据,然后遍历 body,替换库存
for k,v in pairs(data.productList) do
     v.stock_num = productList[""..v.product_id]['stock_num']
end
-- 输出结果

body = "callback(" .. json.encode(data) .. ")"

ngx.say(body)

7.从头验证这些小效率

笔者们把js中的链接更换来http://api.yanshinian.com/product/filter/product.json

在加码壹位作品呈现的仓库储存字段。

<p>img: {{product.img}}</p>

变更数据库。(由于我们那边是demo,所以大家只要,运行后台的数据库,跟超级市场是同3个。真实环境,当然是数据库跟代码都分别的)。

验证是ok的。

b、在nginx.conf同目录创设lua.conf文件尤其存放lua的路由配置

b、在nginx.conf同目录创制lua.conf文件特别存放lua的路由配置

谈到底还想说的

lua代码中有1行注意下local bodyJson = ngx.arg[1]。body_filter阶段是能够对响应数据进行过滤,比如截断、替换。ngx.arg[1]是用来得到响应数据(但也也许得到的不全,那是另叁个标题了)。但是那个阶段有失水准,当作者得到ids参数,实例化http,并发送请求。报错了。报错如下。

2017/08/05 22:08:56 [error] 31159#0: *581 failed to run body_filter_by_lua*: ...local/openresty/lualib/lua-resty-http/lib/resty/http.lua:121: API disabled in the context of body_filter_by_lua*
3797 stack traceback:
3798     [C]: in function 'ngx_socket_tcp'
3799     ...local/openresty/lualib/lua-resty-http/lib/resty/http.lua:121: in function 'new'
3800     /home/nobody/lua/product.lua:20: in function 'http_request'
3801     /home/nobody/lua/product.lua:39: in function </home/nobody/lua/product.lua:1> while sending response to client, client: 192.168.95.1, server: 
......................

也正是说在这一个等级不可能发送接口请求。其它,执行ngx.say
也是分化意的。所以改用content_by_lua 那一个等级
再深刻的细节,大概需求查下。

#lua.conf  
server {  
 charset utf-8; #设置编码
    listen       80;  
    server_name  _;  
 location /user {  
  default_type 'text/html';  
  content_by_lua_file lua/api/userController.lua; #相对于nginx安装目录  
 } 
}    
#lua.conf  
server {  
    charset utf-8; #设置编码
    listen       80;  
    server_name  _;  
    location /user {  
        default_type 'text/html';  
        content_by_lua_file lua/api/userController.lua; #相对于nginx安装目录  
    } 
}    

缓存

缓存是应用 了nginx的特点

修改配置文件即可。

怎么用缓存呢?在此之前作品说了,调用商城接口,仓库储存经常是实时的,量大的情景不难让数据库垮掉。小明给产品申报之后。产品说好能够不那么实时。那样,加上缓存数据库压力就小了。

c、在ngx根目录下的lua文件夹里创造“api”文件夹,并且在其间添加userController.lua
处理文件类,例如代码如下:

c、在ngx根目录下的lua文件夹里创建“api”文件夹,并且在内部添加userController.lua
处理文件类,例如代码如下:

修改 配置文件

nginx.conf 设置 缓存路径

proxy_cache_path /home/nobody/cache levels=1:2 keys_zone=my-cache:8m ina    ctive=1h max_size=10m;proxy_cache_path /home/nobody/cache levels=1:2 keys_zone=my-cache:8m ina    ctive=1h max_size=10m;

api.yanshinian.com.conf,下边扩张如下代码。

 location ^~/product/filter/cache/product.json {
    proxy_pass http://127.0.0.1:8086/product/filter/product.json;
    proxy_cache my-cache;
    proxy_cache_lock on;
    proxy_cache_valid 200 304 1m;#设置一分钟的缓存
    proxy_cache_key $uri$is_args$args;
    add_header Nginx-Cache "$upstream_cache_status";
}

我们把js请求的链接改成
http://api.yanshinian.com//product/filter/cache/product.json。举办呼吁。抓包看下响应头Nginx-Cache。发现Nginx-Cache:HIT。表明缓存成功。

local request_method = ngx.var.request_method
local args = nil

--1、获取参数的值 获取前端提交参数
if "GET" == request_method then
    args = ngx.req.get_uri_args()
elseif "POST" == request_method then
    ngx.req.read_body()
    args = ngx.req.get_post_args()
end

--2、组合url请求Get/Post请求 并获取参数  
local http = require "resty.http"  
local httpc = http.new()  
local url = "http://xxxxx/user/login/"..args["userid"].."/"..args["pass"]
local resStr --响应结果  
local res, err = httpc:request_uri(url, {  
    method = "GET",  
    --args = str,  
     body = "a=1&b=2",
    headers = {  
       ["Content-Type"] = "application/json",  
    }  
})  

--3、开始重新组合参数 例子 可根据返回的JSON自己处理
local cjson = require "cjson"
local sampleJson = [[{"age":"23","testArray":{"array":[8,9,11,14,25]},"Himi":"himigame.com"}]];
--解析json字符串
local data = cjson.decode(sampleJson);
--打印json字符串中的age字段
ngx.say(data["age"]);
--打印数组中的第一个值(lua默认是从0开始计数)
ngx.say(data["testArray"]["array"][1]);  


--4、打印输出新返回值
ngx.say(res.body) 
local request_method = ngx.var.request_method
local args = nil

--1、获取参数的值 获取前端提交参数
if "GET" == request_method then
    args = ngx.req.get_uri_args()
elseif "POST" == request_method then
    ngx.req.read_body()
    args = ngx.req.get_post_args()
end

--2、组合url请求Get/Post请求 并获取参数  
local http = require "resty.http"  
local httpc = http.new()  
local url = "http://xxxxx/user/login/"..args["userid"].."/"..args["pass"]
local resStr --响应结果  
local res, err = httpc:request_uri(url, {  
    method = "GET",  
    --args = str,  
     body = "a=1&b=2",
    headers = {  
       ["Content-Type"] = "application/json",  
    }  
})  

--3、开始重新组合参数 例子 可根据返回的JSON自己处理
local cjson = require "cjson"
local sampleJson = [[{"age":"23","testArray":{"array":[8,9,11,14,25]},"Himi":"himigame.com"}]];
--解析json字符串
local data = cjson.decode(sampleJson);
--打印json字符串中的age字段
ngx.say(data["age"]);
--打印数组中的第一个值(lua默认是从0开始计数)
ngx.say(data["testArray"]["array"][1]);  


--4、打印输出新返回值
ngx.say(res.body) 

附赠二个函数

在骨子里支出中,商城的接口,要求批量调用,做了限定,然而lua
未有array_chunk(不像php)的函数,自个儿包装了二个

function table_chunk(stable, count)
        local newTable = {};
        local tlen = #stable;
        local tempTable = {};
        for k,v in pairs(stable) do
                table.insert(tempTable, v);
                local tempLen = #tempTable;
                if(tempLen % count == 0)  then
                        table.insert(newTable, tempTable);
                        tempTable = {};
                end
        end
        table.insert(newTable, tempTable);
        return newTable;
end

ps.openResty是身边小伙提的方案,作者吧,本身编个代码无非便是抚今追昔下所学的。哈哈。

参考链接:


nginx的proxy_cache缓存相关配置》http://hnr520.blog.51cto.com/4484939/1686896

感兴趣的话能够关心本人的大众号——言拾年的壹般

澳门金沙国际 2

qrcode_for_gh_20daf6d0ff9e_430 (2).jpg

三、运行ngx服务器,访问地址,路由为user  

三、运转ngx服务器,访问地址,路由为user  

 

 

相关文章