Recently, in the company API gateway rewrite, the company uses serverMesh for service registration, invocation, here combined with the previous study of API Gateway Services for a simple summary and analysis. Since a lot of nginx-related stuff has been used, here is a record:
Using openresty in nginx
Add nginx module
Edit the conf configuration file nginx.conf under nginx
# vi nginx.conf //Add in the server module location /helloworld { default_type text/html; content_by_lua 'ngx.say("hello world")'; }
Check that the configuration file is correct
# /usr/local/openresty/nginx/sbin/nginx -t -c /usr/local/openresty/nginx/conf/nginx.conf
Restart nginx
# ./nginx -s reload
Access http://ip/helloworld and output HelloWorld
Internal variables of nginx
Name description Name parameter in the $arg_name request Parameters in the $args request Binary representation of $binary_remote_addr remote address Number of body bytes sent by $body_bytes_sent Content-Length in the $content_length HTTP request information Content-Type in the $content_type request information document_root sets the value for the root path of the current request document_uri is the same as $uri; for example, / test2/test.php "Host" in the $host request information is equal to the server name set if there are no Host rows in the request The $hostname machine name uses the value of the gethostname system call http_cookie cookie information $http_referer reference address $http_user_agent client proxy information The last Ip address to access the server is $http_via. $http_x_forwarded_for corresponds to the network access path is_args returns "?" if the request line has parameters, otherwise it returns an empty string. Restriction of connection rate by $limit_rate The current running nginx version number of $nginx_version The PID of the $pid worker process $query_string is the same as $args $realpath_root calculates the absolute path of the current request as per root or alias instructions. The symbolic links are parsed into real file paths. remote_addr Client IP Address $remote_port client port number remote_user client username for authentication request User request The variable $request_body (0.7.58+) contains the main information of the request. It's more meaningful in location s using proxy_pass or fastcgi_pass instructions request_body_file Client requests temporary filename for principal information request_completion is set to "OK" if the request succeeds; empty if the request is not completed or is not the last part of a series of requests The file path name of the current request for $request_filename, such as / opt/nginx/www/test.php Method of request_method request, such as "GET", "POST", etc. The URI of the $request_uri request with parameters; for example, http://localhost:88/test1/ Protocol used by $scheme, such as http or https server_addr server address. If the server address is not specified by listen, using this variable will initiate a system call to get the address (resulting in waste of resources) Server name to which the $server_name request arrives Server port number to which the $server_port request arrives Protocol version of the $server_protocol request, "HTTP/1.0" or "HTTP/1.1" The URI of the $uri request may be different from the original value, such as redirected.
Test acquisition variables
location /test_url { echo "url:$uri"; } location /test_url { echo "url:$uri"; echo "full url : $host$request_uri"; }
openresty uses redis
Connect to redis server
---Definition redis Method of Closing Connections 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
Establish connection
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
Call API to set key
ok, err = red:set("msg", "hello world") if not ok then ngx.say("set msg error : ", err) return close_redis(red) end
Call the API to get the key value
local resp, err = red:get("msg") if not resp then ngx.say("get msg error : ", err) return close_redis(red) end
redis connection pool
local function close_redis(red) if not red then return end --Release connection(Connection pool implementation) local pool_max_idle_time = 10000 --Millisecond local pool_size = 100 --Connection pool size local ok, err = red:set_keepalive(pool_max_idle_time, pool_size) if not ok then ngx.say("set keepalive error : ", err) end end
Access Frequency Control:
We use redis key to represent the user, value to represent the user's request frequency, and then use expiration time to achieve unit time.
Only 10 frequency requests can be accessed within 10 seconds, exceeding 403 returns
First of all, the nginx.conf configuration file, the nginx.conf part is as follows:
location /frequency { access_by_lua_file /usr/local/lua/access_by_limit_frequency.lua; echo "Successful visit"; }
Edit access_by_limit_frequency.lua
local function close_redis(red) if not red then return end --Release connection(Connection pool implementation) local pool_max_idle_time = 10000 --Millisecond local pool_size = 100 --Connection pool size 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" --Introduce redis Modular local red = redis:new() --Create an object, note that it is called with a colon --Set timeout (milliseconds) red:set_timeout(1000) --Establish connection 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 --Get this client IP Frequency local resp, err = red:get(key) if not resp then close_redis(red) return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) --redis Failure to obtain value end if resp == ngx.null then red:set(key, 1) -- First visit per unit time red:expire(key, 10) --10 Second time expiration end if type(resp) == "string" then if tonumber(resp) > 10 then -- More than 10 times close_redis(red) return ngx.exit(ngx.HTTP_FORBIDDEN) --Direct return 403 end end --call API Set up key ok, err = red:incr(key) if not ok then close_redis(red) return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) --redis Report errors end close_redis(red)
Request address: / frequency
Over 10 times in 10 seconds, return 403
Ten seconds later, it's accessible again.
If we want to add this restriction to the entire website, we just need to
access_by_lua_file /usr/local/lua/access_by_limit_frequency.lua;
This configuration, placed in the server section, allows all location s to apply.