OpenResty 簡單API Server框架

2021-08-12 17:32 更新

實現(xiàn)一個最最簡單的數(shù)學計算:加、減、乘、除,給大家演示如何搭建簡單的 API Server。

按照前面幾章的寫法,先來看看加法、減法示例代碼:

worker_processes  1;        #nginx worker 數(shù)量
error_log logs/error.log;   #指定錯誤日志文件路徑
events {
    worker_connections 1024;
}
http {
    server {
        listen 80;

        # 加法
        location /addition {
           content_by_lua_block {
                local args = ngx.req.get_uri_args()
                ngx.say(args.a + args.b)
            }
        }

        # 減法
        location /subtraction {
            content_by_lua_block {
                local args = ngx.req.get_uri_args()
                ngx.say(args.a - args.b)
            }
        }

        # 乘法
        location /multiplication {
            content_by_lua_block {
                local args = ngx.req.get_uri_args()
                ngx.say(args.a * args.b)
            }
        }

        # 除法
        location /division {
            content_by_lua_block {
                local args = ngx.req.get_uri_args()
                ngx.say(args.a / args.b)
            }
        }
    }
}

代碼寫多了一眼就可以看出來,這么簡單的加減乘除,居然寫了這么長,而且還要對每個 API 都寫一個 location ,作為有追求的人士,怎能容忍這種代碼風格?

  • 首先是需要把這些 location 合并;
  • 其次是這些接口的實現(xiàn)放到獨立文件中,保持 nginx 配置文件的簡潔;

基于這兩點要求,可以改成下面的版本,看上去有那么幾分模樣的樣子:

nginx.conf 內(nèi)容:
worker_processes  1;        #nginx worker 數(shù)量
error_log logs/error.log;   #指定錯誤日志文件路徑
events {
    worker_connections 1024;
}

http {
    # 設置默認 lua 搜索路徑,添加 lua 路徑
    # 此處寫相對路徑時,對啟動 nginx 的路徑有要求,必須在 nginx 目錄下啟動,require 找不到
    # comm.param 絕對路徑當然也沒問題,但是不可移植,因此應使用變量 $prefix 或
    # ${prefix},OR 會替換為 nginx 的 prefix path。

    # lua_package_path 'lua/?.lua;/blah/?.lua;;';
    lua_package_path '$prefix/lua/?.lua;/blah/?.lua;;';

    # 這里設置為 off,是為了避免每次修改之后都要重新 reload 的麻煩。
    # 在生產(chǎn)環(huán)境上務必確保 lua_code_cache 設置成 on。
    lua_code_cache off;

    server {
        listen 80;

        # 在代碼路徑中使用nginx變量
        # 注意: nginx var 的變量一定要謹慎,否則將會帶來非常大的風險
        location ~ ^/api/([-_a-zA-Z0-9/]+) {
            # 準入階段完成參數(shù)驗證
            access_by_lua_file  lua/access_check.lua;

            #內(nèi)容生成階段
            content_by_lua_file lua/$1.lua;
        }
    }
}
其他文件內(nèi)容:
--========== {$prefix}/lua/addition.lua
local args = ngx.req.get_uri_args()
ngx.say(args.a + args.b)

--========== {$prefix}/lua/subtraction.lua
local args = ngx.req.get_uri_args()
ngx.say(args.a - args.b)

--========== {$prefix}/lua/multiplication.lua
local args = ngx.req.get_uri_args()
ngx.say(args.a * args.b)

--========== {$prefix}/lua/division.lua
local args = ngx.req.get_uri_args()
ngx.say(args.a / args.b)

既然對外提供的是 API Server,作為一個服務端程序員,怎么可以容忍輸入?yún)?shù)不檢查呢?萬一對方送過來的不是數(shù)字或者為空,這些都要過濾掉嘛。參數(shù)檢查過濾的方法是統(tǒng)一,在這幾個 API 中如何共享這個方法呢?這時候就需要 Lua 模塊來完成了。

  • 使用統(tǒng)一的公共模塊,完成參數(shù)驗證;
  • 驗證入口最好也統(tǒng)一,不要分散在不同地方;
nginx.conf 內(nèi)容:
worker_processes  1;        #nginx worker 數(shù)量
error_log logs/error.log;   #指定錯誤日志文件路徑
events {
    worker_connections 1024;
}
http {
    server {
        listen 80;

        # 在代碼路徑中使用nginx變量
        # 注意: nginx var 的變量一定要謹慎,否則將會帶來非常大的風險
        location ~ ^/api/([-_a-zA-Z0-9/]+) {
            access_by_lua_file  lua/access_check.lua;
            content_by_lua_file lua/$1.lua;
        }
    }
}
新增文件內(nèi)容:
--========== {$prefix}/lua/comm/param.lua
local _M = {}

-- 對輸入?yún)?shù)逐個進行校驗,只要有一個不是數(shù)字類型,則返回 false
function _M.is_number(...)
    local arg = {...}

    local num
    for _,v in ipairs(arg) do
        num = tonumber(v)
        if nil == num then
            return false
        end
    end

    return true
end

return _M

--========== {$prefix}/lua/access_check.lua
local param= require("comm.param")
local args = ngx.req.get_uri_args()

if not args.a or not args.b or not param.is_number(args.a, args.b) then
    ngx.exit(ngx.HTTP_BAD_REQUEST)
    return
end

看看curl測試結果吧:

$  nginx  curl '127.0.0.1:80/api/addition?a=1'
<html>
<head><title>400 Bad Request</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>
<hr><center>openresty/1.9.3.1</center>
</body>
</html>
$  nginx  curl '127.0.0.1:80/api/addition?a=1&b=3'
4

基本是按照預期執(zhí)行的。參數(shù)不全、錯誤時,會提示400錯誤。正常處理,可以返回預期結果。

來整體看一下目前的目錄關系:

.
├── conf
│   ├── nginx.conf
├── logs
│   ├── error.log
│   └── nginx.pid
├── lua
│   ├── access_check.lua
│   ├── addition.lua
│   ├── subtraction.lua
│   ├── multiplication.lua
│   ├── division.lua
│   └── comm
│       └── param.lua
└── sbin
    └── nginx

怎么樣,有點 magic 的味道不?其實你的接口越是規(guī)范,有固定規(guī)律可尋,那么 OpenResty 就總是很容易能找到適合你的位置。當然這里你也可以把 ?access_check.lua? 內(nèi)容分別復制到加、減、乘、除實現(xiàn)的四個 Lua 文件中,肯定也是能用的。這里只是為了給大家提供更多的玩法,需要的時候可以有更多的選擇。

本章目的是搭建一個簡單API Server,記住這絕對不是終極版本。這里面還有很多需要進一步去考慮的地方,但是作為最基本的框架已經(jīng)有了。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號