nginx match specific word in location

2019-06-17 06:44发布

问题:

I am having trouble matching a specific word in nginx $request_body variable. I want to proxy pass if the body request has a special word in it,

So my approach is this:

 location ~ \.php$ {
if ($request_body ~* (.*)) {                                        
        proxy_pass http://test.proxy;
            break;
    }

# other case...
}

This matches everything and the if statement works, but if I change the regexp in any way, I can't get a hit.

So my question now is:

How do i need to define the regexp in nginx correctly to match against, "target" for example?

Thanks in advance!

回答1:

Your code has a number of problems.

  1. "($request_body ~* (.*))" never matches anything as stated by someone else and so the the "other case" is always the outcome

  2. More importantly, it uses "proxy_pass" with "if" which is classically evil. http://wiki.nginx.org/IfIsEvil.

To get what you want, use the 3rd party ngx_lua module (v0.3.1rc24 and above) ...

location ~ \.php$ { 
    rewrite_by_lua ' 
        ngx.req.read_body() 
        local match = ngx.re.match(ngx.var.request_body, "target") 
        if match then 
            ngx.exec("@proxy");
        else 
            ngx.exec("@other_case");     
        end 
    '; 
} 

location @proxy {    
    # test.proxy stuff 
    ... 
}

location @other_case {
    # other_case stuff 
    ... 
}

You can get ngx_lua at https://github.com/chaoslawful/lua-nginx-module/tags.

PS. Bear in mind that rewrite by lua is always executed after the nginx rewrite directives so if you put any such directives in the other case, they will be executed first and you will get funnies.

You should put all your rewrites within the rewrite by lua context for consistent results. This is the reason for the "if ..else..end" arrangement for the "other case".


You may need this longer version


location ~ \.php$ { 
    rewrite_by_lua '
        --request body only available for POST requests
        if ngx.var.request_method == "POST"
            -- Try to read in request body
            ngx.req.read_body()
            -- Try to load request body data to a variable
            local req_body = ngx.req.get_body_data()
            if not req_body then 
                -- If empty, try to get buffered file name
                local req_body_file_name = ngx.req.get_body_file()
                --[[If the file had been buffered, open it, 
                read contents to our variable and close]] 
                if req_body_file_name then
                    file = io.open(req_body_file_name)
                    req_body = file:read("*a")
                    file:close()
                end
            end
            -- If we got request body data, test for our text
            if req_body then
                local match = ngx.re.match(req_body, "target") 
                if match then 
                    -- If we got a match, redirect to @proxy
                    ngx.exec("@proxy")
                else
                     -- If no match, redirect to @other_case
                    ngx.exec("@other_case")
                end
            end
        else
            -- Pass non "POST" requests to @other_case
            ngx.exec("@other_case")
        end
    ';
}


回答2:

Manual:

Note: for curly braces( { and } ), as they are used both in regexes and for block control, to avoid conflicts, regexes with curly braces are to be enclosed with double quotes (or single quotes).

so try

if ($request_body ~* "(.*)")

Other comments: The code .* matches everything. I would instead use \w, since Perl regex seems to be available.

Your current if -clause is always wrong so no hit is the right output for it.



标签: regex nginx