Расположение Nginx реализует обработку запросов подразделениями, некоторые URI возвращают статический контент, некоторые распространяются на внутренние серверы и т. д. Сегодня давайте подробно разберемся с его правилами сопоставления.
Пример простейшего расположения выглядит следующим образом.
server {
server_name website.com;
location /admin/ {
# The configuration you place here only applies to
# http://website.com/admin/
}
}
синтаксис, поддерживаемый местоположениемlocation [=|~|~*|^~|@] pattern { ... }
, на первый взгляд довольно сложно, давайте рассмотрим его по порядку.
тип модификатора местоположения
Модификатор "=": требует, чтобы путь точно совпадал
server {
server_name website.com;
location = /abcd {
[…]
}
}
-
http://website.com/abcd
совпадение -
http://website.com/ABCD
может соответствовать, или может не совпадать, в зависимости от того, чувствительна ли файловая система операционной системы к регистру. ps: Mac по умолчанию нечувствителен к регистру, и при использовании git будут большие ямы. -
http://website.com/abcd?param1¶m2
совпадение, игнорируя строку запроса -
http://website.com/abcd/
Несоответствие, с окончанием/
-
http://website.com/abcde
Несоответствие
Модификатор "~": обычное соответствие с учетом регистра
server {
server_name website.com;
location ~ ^/abcd$ {
[…]
}
}
^/abcd$
Это регулярное выражение означает, что строка должна начинаться с/
начать с$
конец, середина должна бытьabcd
-
http://website.com/abcd
совпадение(точное совпадение) -
http://website.com/ABCD
Несоответствие,Деликатный случай -
http://website.com/abcd?param1¶m2
совпадение -
http://website.com/abcd/
Несоответствие, который не может соответствовать регулярному выражению -
http://website.com/abcde
Несоответствие, который не может соответствовать регулярному выражению
"~*" регулярное сопоставление без учета регистра
server {
server_name website.com;
location ~* ^/abcd$ {
[…]
}
}
-
http://website.com/abcd
совпадение(точное совпадение) -
http://website.com/ABCD
совпадение(без учета регистра) -
http://website.com/abcd?param1¶m2
совпадение -
http://website.com/abcd/
不匹配
, который не может соответствовать регулярному выражению -
http://website.com/abcde
不匹配
, который не может соответствовать регулярному выражению
Модификатор ## "^~": сопоставление префикса Если расположение является наилучшим соответствием, то этот модификатор больше не выполняет проверку регулярных выражений для строк, соответствующих этому местоположению. Обратите внимание, что это не совпадение с регулярным выражением, оно должно иметь приоритет над совпадением с регулярным выражением.
Найти порядок и приоритет
При наличии нескольких правил локации у nginx более сложный набор правил, приоритеты следующие:
- точное совпадение
=
- совпадение префикса
^~
(Немедленно прекратите последующие регулярные поиски) - Регулярное сопоставление по порядку в файлах
~
или~*
- Соответствует префиксу, соответствует без каких-либо модификаций.
Общая идея этого правила такова.
Сначала точное совпадение, без поиска
^~
Если сопоставление префикса отсутствует, выполняется обычное сопоставление, и, наконец, возвращается результат сопоставления префикса (если есть).
Если приведенные выше правила непросты для понимания, вы можете увидеть следующий псевдокод (очень важно)
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] // 注意这里没有 return,且这里是最长匹配
if uri in regex_match:
return regex_match[uri] // 按文件中顺序,找到即返回
return rv
упрощенныйNode.js
Написанный код выглядит следующим образом
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;
}
анализ случая
Дело 1
server {
server_name website.com;
location /doc {
return 701; # 用这样的方式,可以方便的知道请求到了哪里
}
location ~* ^/document$ {
return 702; # 用这样的方式,可以方便的知道请求到了哪里
}
}
curl -I website.com:8080/document
HTTP/1.1 702
Согласно приведенным выше правилам, второй будет иметь более высокий приоритет.
Случай 2
server {
server_name website.com;
location /document {
return 701;
}
location ~* ^/document$ {
return 702;
}
}
curl -I website.com:8080/document
Второе соответствует регулярному выражению и имеет приоритет над первым нормальным соответствием префикса.
Случай 3
server {
server_name website.com;
location ^~ /doc {
return 701;
}
location ~* ^/document$ {
return 702;
}
}
curl http://website.com/document
HTTP/1.1 701
первое совпадение префикса^~
После попадания не будет искать обычные совпадения, поэтому будет первым попаданием
Случай 4
server {
server_name website.com;
location /docu {
return 701;
}
location /doc {
return 702;
}
}
curl -I website.com:8080/document
возвращениеHTTP/1.1 701
,
server {
server_name website.com;
location /doc {
return 702;
}
location /docu {
return 701;
}
}
curl -I website.com:8080/document
все еще возвращаюсьHTTP/1.1 701
При сопоставлении префикса возвращается самое длинное совпадающее местоположение, независимо от порядка расположения.
Случай 5
server {
listen 8080;
server_name website.com;
location ~ ^/doc[a-z]+ {
return 701;
}
location ~ ^/docu[a-z]+ {
return 702;
}
}
curl -I website.com:8080/document
возвращениеHTTP/1.1 701
изменить порядок
server {
listen 8080;
server_name website.com;
location ~ ^/docu[a-z]+ {
return 702;
}
location ~ ^/doc[a-z]+ {
return 701;
}
}
curl -I website.com:8080/document
возвращениеHTTP/1.1 702
Обычное сопоставление заключается в использовании порядка в файле, поиске и возврате