API Gateway [gateway] 3

Keywords: Java Nginx Redis PHP network

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.

Posted by toma42 on Fri, 10 May 2019 00:48:40 -0700