API網關【gateway 】- 3

最近在公司進行API網關重寫,公司內採用serverMesh進行服務註冊,調用,這裏結合以前學習對API網關服務進行簡單的總結與分析。 因爲採用了大量的nginx相關的東西,因此在此記錄一下:php

在nginx使用openrestyhtml

加入nginx模塊nginx

編輯nginx下conf配置文件nginx.confredis

# vi nginx.conf
在server模塊加上
location /helloworld {
default_type text/html;
content_by_lua 'ngx.say("hello world")';
}

 檢查配置文件是否正確服務器

# /usr/local/openresty/nginx/sbin/nginx -t -c /usr/local/openresty/nginx/conf/nginx.conf

重啓nginxcookie

# ./nginx -s reload

訪問http://ip/helloworld ,輸出helloworld網絡

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指令算出的當前請求的絕對路徑。其中的符號連接都會解析成真是文件路徑
$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,帶參數; 好比http://localhost:88/test1/
$scheme 所用的協議,好比http或者是https
$server_addr 服務器地址,若是沒有用listen指明服務器地址,使用這個變量將發起一次系統調用以取得地址(形成資源浪費)
$server_name 請求到達的服務器名
$server_port 請求到達的服務器端口號
$server_protocol 請求的協議版本,"HTTP/1.0""HTTP/1.1"
$uri 請求的URI,可能和最初的值有不一樣,好比通過重定向之類的

測試獲取變量測試

location /test_url {
    echo "url:$uri";
}

location /test_url {
            echo "url:$uri";
            echo "full url : $host$request_uri";
}

openresty 使用redis網站

鏈接redis服務器

---定義 redis關閉鏈接的方法
local function close_redis(red)  
    if not red then  
        return  
    end  
    local ok, err = red:close()  
    if not ok then  
        ngx.say("close redis error : ", err)  
    end  
end  

創建鏈接

local ip = "192.168.31.247"  
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  

調用API設置key  

ok, err = red:set("msg", "hello world")  
if not ok then  
    ngx.say("set msg error : ", err)  
    return close_redis(red)  
end  

調用API獲取key值

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

redis鏈接池

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  

訪問頻率控制:

咱們用redis的key表示用戶,value表示用戶的請求頻次,再利用過時時間實現單位時間

要求10秒內只能訪問10次frequency請求,超過返回403

首先爲nginx.conf配置文件,nginx.conf部份內容以下:

location /frequency {
    access_by_lua_file /usr/local/lua/access_by_limit_frequency.lua;
    echo "訪問成功";
}

編輯access_by_limit_frequency.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 function errlog(...)
    ngx.log(ngx.ERR, "redis: ", ...)
end

local redis = require "resty.redis"  --引入redis模塊
local red = redis:new()  --建立一個對象,注意是用冒號調用的

--設置超時(毫秒)  
red:set_timeout(1000) 
--創建鏈接  
local ip = "192.168.31.247"  
local port = 6379
local ok, err = red:connect(ip, port)
if not ok then  
    close_redis(red)
    errlog("Cannot connect");
    return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)   
end  

local key = "limit:frequency:login:"..ngx.var.remote_addr

--獲得此客戶端IP的頻次
local resp, err = red:get(key)
if not resp then  
    close_redis(red)
    return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) --redis 獲取值失敗
end 

if resp == ngx.null then   
    red:set(key, 1) -- 單位時間 第一次訪問
    red:expire(key, 10) --10秒時間 過時
end  

if type(resp) == "string" then 
    if tonumber(resp) > 10 then -- 超過10次
        close_redis(red)
        return ngx.exit(ngx.HTTP_FORBIDDEN) --直接返回403
    end
end

--調用API設置key  
ok, err = red:incr(key)  
if not ok then  
    close_redis(red)
    return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) --redis 報錯 
end  

close_redis(red)  

請求地址:/frequency

10秒內 超出10次 ,返回403

10秒後,又能夠訪問了

若是咱們想整個網站 都加上這個限制條件,那隻要把

access_by_lua_file /usr/local/lua/access_by_limit_frequency.lua;

這個配置,放在server部分,讓全部的location 適用就好了

相關文章
相關標籤/搜索