Dynamic Redirects

agentzh agentzh at gmail.com
Wed Jul 27 03:48:11 UTC 2011


On Thu, Apr 8, 2010 at 3:09 AM, Harmer, Sean <seanharmer at gmail.com> wrote:
> NGINX Team,
>
> Is there a way to capture the User-Agent from an HTTP Header, then query a
> database for that User-Agent, then based on the result of the database
> query, transparently route the request to an appropriate server?
>

I've got a sample app running to demonstrate this, using our
opensource modules ngx_redis2, ngx_lua, and ngx_set_misc:

    https://github.com/agentzh/redis2-nginx-module

    http://github.com/chaoslawful/lua-nginx-module

    https://github.com/agentzh/set-misc-nginx-module

Here's the complete code listing for my nginx.conf:

    worker_processes  1;
    error_log logs/error.log info;
    events {
        worker_connections 1024;
    }
    http {
        upstream apache.org {
            server 140.211.11.131;
        }

        upstream nginx.org {
            server 206.251.255.63;
        }

        server {
            listen 8080;

            location = /redis {
                internal;
                set_unescape_uri $key $arg_key;
                redis2_query get $key;
                redis2_pass 127.0.0.1:6379;
            }

            location / {
                set $target '';
                access_by_lua '
                    local key = ngx.var.http_user_agent
                    local res = ngx.location.capture(
                        "/redis", { args = { key = key } }
                    )

                    print("key: ", key)

                    if res.status ~= 200 then
                        ngx.log(ngx.ERR, "redis server returns bad status: ",
                            res.status)
                        ngx.exit(res.status)
                    end

                    if not res.body then
                        ngx.log(ngx.ERR, "redis returned empty body")
                        ngx.exit(500)
                    end

                    -- we can use the lua-redis-parser library to
parse the reply
                    -- here instead
                    local server = string.match(res.body,
                               "^$%d+\\r\\n(%S+)\\r\\n")
                    if not server then
                        ngx.log(ngx.ERR, "bad redis response: ", res.body)
                        ngx.exit(500)
                    end

                    print("server: ", server)

                    ngx.var.target = server
                ';

                proxy_pass http://$target;
            }
        }
    }

This version is longer than the one using ngx_eval, but with much
saner error handling.

And then let's start the redis server on the localhost:6379:

    ./redis-server  # default port is 6379

and feed some keys into this using the redis-cli utility:

    $ ./redis-cli
    redis> set foo apache.org
    OK
    redis> set bar nginx.org
    OK

And then let's test our nginx app!

    $ curl --user-agent foo localhost:8080
    <apache.org home page goes here>

    $ curl --user-agent bar localhost:8080
    <nginx.org home page goes here>

To further tune the performance, one could enable the connection pool
for the redis connections, as documented in ngx_redis2's README.

You can consider using the ngx_openresty bundle to run this sample to
eliminate all the pain involved in downloading and enabling 3rd-party
modules by yourself ;)

    http://openresty.org/

Regards,
-agentzh



More information about the nginx mailing list