1

I've got a case where I want to proxy a particular call down to a different backend based on the existence of a query param. The following is sort of what I start with

location ~ ^/abc/xyz/?$ {
    proxy_pass $backend_url;
 }

What I'd like to do is check for a query param foo (or even just the existence of that string anywhere). So I thought I could do this

location ~ ^/abc/xyz/?$ {
    set $backend_url "somelocation"

    if ($request_url ~ .*foo.*) {
       set $backend_url "someotherlocation"
       proxy_pass $backend_url
    }
    proxy_pass $backend_url;
 }

But this doesn't seem to actually proxy to the new location. Am I doing something wrong with my code, or is the whole approach wrong?

1 Answer 1

1

I don't know why are you using two proxy_pass directives, this block should do it in a logic you described:

location ~ ^/abc/xyz/?$ {
    set $backend_url "somelocation";
    if ($request_url ~ \?(.*&)?foo(=|&|$)) {
       set $backend_url "otherlocation";
    }
    proxy_pass $backend_url;
 }

I slightly modified your regex to match only request URLs where foo is a query argument name and not a query argument value (or its part). However I'd rather use map directive for this purpose (map block should be placed outside the server block):

map $arg_foo $backend_url {
    ""      somelocation;  # if the value is empty
    default otherlocation; # otherwise
}

server {
    ...
    location ~ ^/abc/xyz/?$ {
        proxy_pass $backend_url;
    }
}

Pay an attention you may need to define a resolver for this configuration to work (some additional info about this can be found here).

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks! I put th proxy_pass in there because in the real version of the code, there's a bit more stuff modifying the backend_url (some Lua module). But it might not be needed.
Re: your second suggestion - does arg_foo do something special (ie. Extract a query param named foo) or do I need to something to populate that?
Yes, you are right, $arg_name are special nginx variables to extract according query arguments (here is the description). About your first comment - actually every if block is a virtual nested location that's trying to inherit all available directives from the previous level (sometimes including even those than are not normally inherited), so it isn't make a big difference.
if directive behaviour sometimes extremely unclear. An excellent explanation on how an if location works is made by Yichun Zhang, an author of lua-nginx-module and the OpenResty nginx fork: How nginx "location if" works

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.