03月02, 2018

Nginx的location指令配置

在编写nginx配置中,正确的配置location指令是相当重要的。笔者在一次问题的排查中仔细研究了下这个指令的规则和使用方法,在这里和大家分享一下,如有不正确的地方还望指正。

指令语法

location [ 限定符 ] 规则uri { 指令集 }

在一个请求的处理流程中,nginx会启动一个location的查找过程,在这个过程中nginx会根据一定的规则用请求的request_uri有选择的去匹配这些定义好的规则uri,之后会找到要应用的唯一的location,并应用这个location定义的指令集中的指令。

这里面最关键的地方,就是location的查找过程是如何进行的。要明白这个过程,首先需要知道规则uri是如何定义的。

规则uri

规则uri分为三种类型,nginx对这几种类型执行的匹配方法是不同的:

1. 对限定符为=的规则执行完全匹配

完全匹配例:location = index.php {},那么仅有请求:http://domain/index.php才能匹配,http://domain/index.phpp或http://domain/iindex.php这种均无法匹配。

2. 对限定符为^~或没有限定符规则执行前缀匹配。

前缀匹配例:location /abc {}或location ^~ /abc {},那么请求:http://domain/abcd、http://domain/abc.php这种均能匹配。

3. 对限定符为~~*的规则执行正则匹配。

正则匹配例:location ~ .php$ {},那么请求:http://domain/abc.php、http://domain/abcd.php这种均可以匹配。

location的查找过程

首先会对所有的等号规则前缀规则进行一次匹配筛选。nginx会在所有的前缀匹配中找到一个最长的匹配,然后记住这个匹配的location。之后会根据这个匹配规则是否有限定符来决定之后的行为:

  1. 如果是等号规则匹配到的,nginx会立即结束查找过程,这个location就是最终结果。

  2. 如果匹配到的规则被限定符^~修饰,则nginx也会结束这个查找过程,这个location就是最终结果。

  3. 如果没有找到匹配或是匹配项没有被限定符修饰,nginx就会进入正则规则的匹配筛选过程。在这个过程中,nginx会按照规则uri在配置中定义的顺序来进行匹配,只要匹配到其中一个,nginx就会立即结束这个匹配过程,这个location也会是最终location。如果没有能找到一个正则匹配,但是之前的前缀匹配成功,那么之前记住的前缀匹配结果则会成为最终结果。

通过上面的查找过程,如果成功找到匹配的location,则会执行执行这个location定义的指令集中的指令。

实例说明

下面举几个例子来看一下:假设用户均访问http://www.vmc7.com/abc

1. =命中,跳过正则匹配

server {
    listen 80;

    server_name www.vmc7.com;

    location /abc {}

    location = /abc {}

    location ~ /abc {}
}

2. ^~命中,跳过正则匹配

server {

    listen 80;

    server_name www.vmc7.com;

    location /ab {}

    location ^~ /abc {}

    location ~ /abc {}
}

3. 正则命中1,正则匹配优先于前缀匹配

server {
    listen 80;

    server_name www.vmc7.com;

    location /abc {}

    location ~ /ab.* {}
}

4. 正则命中2,正则按顺序匹配

server {
    listen 80;

    server_name www.vmc7.com;

    location /ab {}

    location ~ /ab.* {}
    location ~ /abc {}
}

5. 前缀命中,正则匹配不到,使用之前命中的前缀匹配

server {
    listen 80;

    server_name www.vmc7.com;

    location /abc {}

    location ~ /ef.* {}
}

最后附上伪代码用以描述整个过程

location = findLocation();
if (location != null) {
    runLocationCmdSet();
}

function findLocation()
{
    finalLocation  = null;
    prefixLocation = null;
    regexLocation  = null;

    prefixLocation = findByPrefix();
    if (prefixLocation != null) {
        if (preceding(prefixLocation) == '=') {
            return prefixLocation;
        }

        if (preceding(prefixLocation) == '^~') {
            return prefixLocation;
        }
    }

    regexLocation = findByRegex();
    finalLocation = (regexLocation == null) ? prefixLocation : regexLocation;

    return finalLocation;
}

function findByPrefix()
{
    result    = null;
    maxLength = 0;

    for (location in allPrefixLocation) {
        if ((matchLength = prefixMatch(location))!= 0) {
            if (matchLength > maxLength) {
                maxLength = matchLength;
                result    = location;
            }
        }
    }

    return result;
}

function findByRegex()
{
    for (location in allRegexLocation) {
        if (regexMatch(location)) {
            return location;
        }
    }

    return null;
}

http://blog.7rule.com/2018/02/20/nginx-location.html

本文链接:https://www.opsdev.cn/post/nginx-location.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。