Understand Nginx location matching thoroughly

Nginx's location implements fine-grained processing of requests, some URI s return static content, some distribute to back-end servers, and so on. Understand its matching rules thoroughly today

An example of the simplest location is as follows

server {
    server_name website.com;
    location /admin/ {
    # The configuration you place here only applies to
    # http://website.com/admin/
    }
}
Copy Code

The syntax supported by location [=|~|~*|^~|@] pattern {...} is complex at first glance, so look at it one by one.

location modifier type

"=" modifier: requires path to match exactly

server {
    server_name website.com;
    location = /abcd {
    [...]
    }
}
Copy Code
  • http://website.com/abcd match
  • http://website.com/ABCD may or may not match, depending on whether the operating system's file system is case-sensitive.ps: Mac defaults to case insensitive, git usage can have pits.
  • Http://website.com/abcd?Param1&param2 match, querystring ignored
  • http://website.com/abcd/mismatch, with end/
  • http://website.com/abcde mismatch

"~" modifier: case-sensitive regular matching

server {
    server_name website.com;
    location ~ ^/abcd$ {
    [...]
    }
}
Copy Code

^/abcd$This regular expression means that the string must start with/end with $and be ABCD in the middle

  • http://website.com/abcd match (exact match)
  • http://website.com/ABCD mismatch, case sensitive
  • Http://website.com/abcd?Param1&param2 match
  • http://website.com/abcd/mismatch, cannot match regular expression
  • http://website.com/abcde does not match, cannot match regular expression

'~*'case-insensitive regular matching

server {
    server_name website.com;
    location ~* ^/abcd$ {
    [...]
    }
}
Copy Code
  • http://website.com/abcd match (exact match)
  • http://website.com/ABCD match (case insensitive)
  • Http://website.com/abcd?Param1&param2 match
  • http://website.com/abcd/ does not match, cannot match regular expression
  • http://website.com/abcde does not match, cannot match regular expression

##'^~'modifier: Prefix matching If the location is the best match, then the modifier will no longer detect regular expressions for strings that match this location.Note that this is not a regular expression match; its purpose is to take precedence over regular expression matching

Order and priority of lookup

When there are multiple location rules, nginx has a more complex set of rules with the following priority:

  • Exact Match =
  • Prefix matches ^~ (stops subsequent regular searches immediately)
  • Regular Matching in File Order ~or ~*
  • Matches prefix matches without any modifications.

The general idea behind this rule is

Precise matching, prefix matching with ^~is found for none, regular matching for none, and prefix matching results are returned (if any)

If the above rules are not easy to understand, you can see the following pseudocode (very important)

function match(uri):
  rv = NULL
  
  if uri in exact_match:
    return exact_match[uri]
  
  if uri in prefix_match:
    if prefix_match[uri] is '^~':
      return prefix_match[uri]
    else:
      rv = prefix_match[uri] // Notice that there is no return,And here is the longest match
   
  if uri in regex_match:
    return regex_match[uri] // Find and return in file order
  return rv
Copy Code

The code written by a simplified Node.js is as follows

function ngx_http_core_find_location(uri, static_locations, regex_locations, named_locations, track) {
  let rc = null;
  let l = ngx_http_find_static_location(uri, static_locations, track);
  if (l) {
    if (l.exact_match) {
      return l;
    }
    if (l.noregex) {
      return l;
    }
    rc = l;
  }
  if (regex_locations) {
    for (let i = 0 ; i < regex_locations.length; i ++) {
      if (track) track(regex_locations[i].id);
      let n = null;
      if (regex_locations[i].rcaseless) {
        n = uri.match(new RegExp(regex_locations[i].name));
      } else {
        n = uri.match(new RegExp(regex_locations[i].name), "i");
      }
      if (n) {
        return regex_locations[i];
      }
    }
  }

  return rc;
}
Copy Code

case analysis

Case 1

server {
    server_name website.com;
    location /doc {
        return 701; # In this way, it is easy to know where the request is going
    }
    location ~* ^/document$ {
        return 702; # In this way, it is easy to know where the request is going

    }
}

curl -I  website.com:8080/document
HTTP/1.1 702
Copy Code

The second has a higher priority according to the above rules

Case 2

server {
    server_name website.com;
    location /document {
        return 701;
    }
    location ~* ^/document$ {
        return 702;
    }
}
curl -I  website.com:8080/document

Copy Code

The second matches the regular expression and takes precedence over the first common prefix match

Case 3

server {
    server_name website.com;
    location ^~ /doc {
        return 701;
    }
    location ~* ^/document$ {
        return 702;
    }
}
curl http://website.com/document
HTTP/1.1 701
Copy Code

First prefix match ^~No more regular matches will be searched after hits, so the first hit will occur

Case 4

server {
    server_name website.com;
    location /docu {
        return 701;
    }
    location /doc {
        return 702;
    }
}
Copy Code

Curl-I website.com:8080/document returns HTTP/1.1 701,

server {
    server_name website.com;
    location /doc {
        return 702;
    }
    location /docu {
        return 701;
    }
}
Copy Code

Curl-I website.com:8080/document still returns HTTP/1.1 701

Under prefix matching, returns the longest matching location regardless of the location order

Case 5

server {
	listen 8080;
	server_name website.com;

    location ~ ^/doc[a-z]+ {
        return 701;
    }

    location ~ ^/docu[a-z]+ {
        return 702;
    }
}
Copy Code

Curl-I website.com:8080/document returns HTTP/1.1 701

Change the order

server {
	listen 8080;
	server_name website.com;

    location ~ ^/docu[a-z]+ {
        return 702;
    }
    
    location ~ ^/doc[a-z]+ {
        return 701;
    }
}
Copy Code

Curl-I website.com:8080/document returns HTTP/1.1 702

Regular matching uses the order in the file to find returns

Keywords: Programming curl Nginx Mac git

Added by pavanpuligandla on Mon, 30 Dec 2019 06:15:04 +0200