最近在公司進行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 適用就好了