Some URIs return static content, some are distributed to back-end servers, etc. Today, to understand its matching rules

The simplest example of a location is as follows

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

Location support of syntactic location [= | | | ~ ~ * ^ ~ | @] pattern {… }, it looks complicated at first glance. Let’s take a look at each one.

Location decorator type

The “=” modifier: Requires paths to match exactly

server {
    server_name website.com;
    location = /abcd {
    […]
    }
}
Copy the code
  • http://website.com/abcdmatching
  • http://website.com/ABCDMight matchOr not, depending on whether the operating system’s file system is case-sensitive. Ps: Mac is case insensitive by default, git use will be a big hole.
  • http://website.com/abcd?param1&param2matchingThe querystring are ignored.
  • http://website.com/abcd/Don’t match“With an ending/
  • http://website.com/abcdeDon’t match

“~” modifier: case-sensitive regular match

server { server_name website.com; Location ~ ^/abcd${[... }}Copy the code

^/abcd$This regular expression indicates that the string must start with a slash, end with $, and be abcd in the middle

  • http://website.com/abcdmatching(Perfect match)
  • http://website.com/ABCDDon’t match, case sensitive
  • http://website.com/abcd?param1&param2matching
  • http://website.com/abcd/Don’t matchCannot match the regular expression
  • http://website.com/abcdeDon’t matchCannot match the regular expression

“~*” is a case-insensitive regular match

server { server_name website.com; Location ~* ^/abcd${[... }}Copy the code
  • http://website.com/abcdmatching(Perfect match)
  • http://website.com/ABCDmatching(Case insensitive)
  • http://website.com/abcd?param1&param2matching
  • http://website.com/abcd/ Don't matchCannot match the regular expression
  • http://website.com/abcde Don't matchCannot match the regular expression

## “^~” modifier: prefix match If the location is the best match, then regular expression checking is no longer performed on strings that match the location. Note that this is not a regular expression match; it is intended to take precedence over regular expression matches

Order and priority of the search

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

  • An exact match=
  • Prefix matching^ ~(Stop subsequent re searches immediately)
  • Regex matches in order of file~or~ *
  • Matches prefix matches without any decorations.

The general idea of the rule is this

A prefix match with ^~ is searched for if there is none, a regular match is performed if there is none, and the result of the prefix match (if any) is returned.

If the above rules are hard to understand, look at 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] // Note that this is not presentreturn, and here is the longest matchif uri in regex_match:
    returnRegex_match [uri] // Return if foundreturn rv
Copy the code

A simplified Node.js code looks like this

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) {
        returnregex_locations[i]; }}}return rc;
}
Copy the 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 702Copy the code

According to the above rules, the second will have higher priority

Case 2

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

Copy the code

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

Case 3

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

After the first prefix match ^~ is hit, the re match is not searched, so it is hit first

Case 4

server {
    server_name website.com;
    location /docu {
        return 701;
    }
    location /doc {
        return702; }}Copy the code

The curl -i website.com: 8080 / document to return to the HTTP / 1.1 701,

server {
    server_name website.com;
    location /doc {
        return 702;
    }
    location /docu {
        return701; }}Copy the code

The curl -i website.com: 8080 / document still returns the HTTP / 1.1 701

Under prefix matching, the longest location matching is returned, regardless of the location order

Case 5

server {
	listen 8080;
	server_name website.com;

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

    location ~ ^/docu[a-z]+ {
        return702; }}Copy the code

The curl -i website.com: 8080 / document back to HTTP / 1.1 701

Let’s switch the order

server {
	listen 8080;
	server_name website.com;

    location ~ ^/docu[a-z]+ {
        return 702;
    }
    
    location ~ ^/doc[a-z]+ {
        return701; }}Copy the code

The curl -i website.com: 8080 / document back to HTTP / 1.1 702

Re matching is returned using the order found in the file