Search code examples
nginxluaopenresty

proxy_pass request base on the result of another internal request via lua-nginx


I want to proxy_pass a request or return a response base on the result of an internal service. to accomplish this purpose I'm using openresty docker image

Here is my nginx.conf:

# nginx.vh.default.conf  --  docker-openresty
#
# This file is installed to:
#   `/etc/nginx/conf.d/default.conf`
#
# It tracks the `server` section of the upstream OpenResty's `nginx.conf`.
#
# This config (and any other configs in `etc/nginx/conf.d/`) is loaded by
# default by the `include` directive in `/usr/local/openresty/nginx/conf/nginx.conf`.
#
# See https://github.com/openresty/docker-openresty/blob/master/README.md#nginx-config-files
#
# load_module /usr/lib/nginx/modules/ndk_http_module.so;
# load_module /usr/lib/nginx/modules/ngx_http_lua_module.so;
lua_package_path '/usr/local/nginx/includes.d/?.lua;/home/user/lua/?.lua;/home/lua/?.lua;;';

error_log  logs/error.log  info;
error_log  logs/error.log  debug;

upstream flask_webservice {
    server challenge:5000;
}

server {
    listen 80;
    server_name  localhost;
    lua_need_request_body on;
    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        # default_type text/plain;
        # proxy_pass http://challenge:5000/;
        content_by_lua_file /home/user/lua/proxy_middleware.lua;
        # content_by_lua_block {}
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/local/openresty/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           /usr/local/openresty/nginx/html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}

Here is proxy_middleware.lua:

local http = require "resty.http"
local cjson = require "cjson"

local httpc = http.new()

local challenge_url = "http://" .. ngx.var.flask_webservice .. ngx.var.uri
local request_header = ngx.req.get_headers()
local request_method = ngx.req.get_method()
local request_body = ngx.req.get_body_data()

if request_body == nil then
    request_body = {}
end

if request_header == nil then
    request_header = {}
end

ngx.log(ngx.DEBUG, challenge_url)
ngx.log(ngx.DEBUG, "request_header: " .. cjson.encode(request_header))
ngx.log(ngx.DEBUG, "request_method: " .. request_method)
ngx.log(ngx.DEBUG, "request_body: " .. cjson.encode(request_body))

local res, err = httpc:request_uri(challenge_url, {
    method = request_method,
    headers = request_header,
    body = request_body
})

ngx.log(ngx.DEBUG, "response is:" .. cjson.encode(res))
ngx.log(ngx.DEBUG, "error is:" .. cjson.encode(err))

here is the error that I have got:

2020/12/24 19:17:52 [error] 7#7: *3 lua entry thread aborted: runtime error: /home/user/lua/proxy_middleware.lua:6: attempt to concatenate field 'flask_webservice' (a nil value)

here is the project on the Github repo

I have two questions:

  1. Is there another way to accomplish this purpose?
  2. How can I access the upstream server in the Lua code?

Solution

  • I managed the first request via resty-http and then use ngx.location.capture to proxy_pass the request based on the result of first request's response

    Here is lua_middleware.lua:

    local http = require "resty.http"
    local cjson = require "cjson"
    
    local httpc = http.new()
    
    local challenge_url = "http://challenge:5000" .. ngx.var.uri
    local request_header = ngx.req.get_headers()
    local request_method = ngx.req.get_method()
    local request_body = ngx.req.get_body_data()
    
    if request_body == nil then
        request_body = {}
    end
    
    if request_header == nil then
        request_header = {}
    end
    
    ngx.log(ngx.DEBUG, challenge_url)
    ngx.log(ngx.DEBUG, "request_header: " .. cjson.encode(request_header))
    ngx.log(ngx.DEBUG, "request_method: " .. request_method)
    ngx.log(ngx.DEBUG, "request_body: " .. cjson.encode(request_body))
    
    local res, err = httpc:request_uri(challenge_url, {
        method = request_method,
        headers = request_header,
        body = request_body
    })
    
    local response_body = res.body
    local response_headers = res.headers
    local response_status = res.status
    
    ngx.log(ngx.DEBUG, "response_body: " .. cjson.encode(response_body))
    ngx.log(ngx.DEBUG, "response_headers: " .. cjson.encode(response_headers))
    ngx.log(ngx.DEBUG, "response_status: " .. cjson.encode(response_status))
    ngx.log(ngx.DEBUG, "error: " .. cjson.encode(err))
    
    ngx.log(ngx.DEBUG, "logger: " .. response_status == 200)
    ngx.log(ngx.DEBUG, "status type: " .. type(response_status))
    
    if response_status == 200 then
        ngx.log(ngx.DEBUG, "Redirecting ...")
        local redirected_res = ngx.location.capture("/redirect_to", {
            method = ngx.HTTP_POST,
            always_forward_body = true
        })
        ngx.log(ngx.DEBUG, "redirect res body: " .. cjson.encode(redirected_res.body))
        ngx.log(ngx.DEBUG, "redirect res status: " .. cjson.encode(redirected_res.status))
    
        ngx.status = redirected_res.status
        ngx.say(redirected_res.body)
        ngx.exit(ngx.HTTP_OK)
    
    else
        ngx.status = response_status
        ngx.say(response_body)
        ngx.exit(ngx.HTTP_OK)
    end
    

    and here is my nginx.conf:

    # nginx.vh.default.conf  --  docker-openresty
    #
    # This file is installed to:
    #   `/etc/nginx/conf.d/default.conf`
    #
    # It tracks the `server` section of the upstream OpenResty's `nginx.conf`.
    #
    # This config (and any other configs in `etc/nginx/conf.d/`) is loaded by
    # default by the `include` directive in `/usr/local/openresty/nginx/conf/nginx.conf`.
    #
    # See https://github.com/openresty/docker-openresty/blob/master/README.md#nginx-config-files
    #
    # load_module /usr/lib/nginx/modules/ndk_http_module.so;
    # load_module /usr/lib/nginx/modules/ngx_http_lua_module.so;
    lua_package_path '/usr/local/nginx/includes.d/?.lua;/home/user/lua/?.lua;/home/lua/?.lua;;';
    
    error_log  logs/error.log  info;
    error_log  logs/error.log  debug;
    
    upstream flask_webservice {
        server challenge:5000;
    }
    
    server {
        listen 80;
        server_name  localhost;
        resolver 127.0.0.11;
        lua_need_request_body on;
        #charset koi8-r;
        #access_log  /var/log/nginx/host.access.log  main;
    
        location / {
            client_max_body_size 50k;
            client_body_buffer_size 50k;
    
            # default_type text/plain;
            # proxy_pass http://challenge:5000/;
            content_by_lua_file /home/user/lua/proxy_middleware.lua;
        }
    
        location /redirect_to {
            proxy_pass http://challenge:5000/arvan;
        }
    
        #error_page  404              /404.html;
    
        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/local/openresty/nginx/html;
        }
    
        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}
    
        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           /usr/local/openresty/nginx/html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}
    
        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }
    

    and here is the project link