Текст на 10 000 слов! Разберитесь в 11 этапах обработки HTTP-запросов Nginx одновременно

Linux

Весь процесс обработки Nginx HTTP-запроса

я уже говорил тебеКак Nginx обрабатывает заголовки HTTP-запросов, следующим шагом будет фактическая обработка HTTP-запроса. Посмотрите на картинку ниже.Это схематическая диаграмма обработки HTTP-запросов Nginx.Несмотря на простоту, она очень хорошо иллюстрирует весь процесс.

  1. Чтение заголовков запроса: анализ заголовков запроса.
  2. Определите блок конфигурации: определите, какое расположение обрабатывает соответствующий URL-адрес.
  3. Применить ограничения скорости: определите, следует ли ограничивать скорость. Например, количество одновременных подключений для этого запроса может превышать лимит, или количество запросов в секунду может быть слишком высоким.
  4. Выполнить аутентификацию: контроль подключения, запрос аутентификации. Например, некоторые настройки анти-лича могут быть сделаны по заголовку Referrer или могут быть проверены полномочия пользователя.
  5. Генерировать контент: генерировать ответ пользователю. Чтобы сгенерировать этот ответ, обратный прокси-сервер может связываться с восходящей службой (восходящие службы), а затем в этом процессе могут быть некоторые подзапросы или перенаправления, затем этот процесс будет сопровождаться (внутренние перенаправления и подзапросы).
  6. Фильтры ответов: фильтруйте ответы, возвращаемые пользователю. Например, сжатие ответов или обработка изображений.
  7. Журнал: запись журнала.

Вышеупомянутые семь шагов представляют поток обработки в целом, и фактический процесс обработки будет описан ниже.

11 этапов обработки HTTP-запросов Nginx

Ниже подробно описаны этапы 11. Каждый этап может соответствовать одному или нескольким модулям HTTP. Благодаря такому сравнению модулей мы также можем хорошо понять, как эти модули работают.

  1. POST_READ: после прочтения заголовка запроса, прежде чем выполнять какую-либо обработку заголовка, если вы хотите получить некоторые исходные значения, вы должны обработать их на этом этапе. Это будет включать модуль realip.
  2. SERVER_REWRITE: Как и в приведенной ниже фазе ПЕРЕЗАПИСЬ, существует только один модуль, называемый модулем перезаписи, и, как правило, никакие сторонние модули не будут обрабатывать эту фазу.
  3. FIND_CONFIG: в настоящее время для сопоставления местоположения ни один модуль не будет использовать его.
  4. ПЕРЕПИСАТЬ: Сделайте что-нибудь с URL.
  5. POST_WRITE: после REWRITE на этом этапе модуль не появится.

Далее идут три модуля, которые подтверждают права доступа пользователя:

  1. ПРЕДВАРИТЕЛЬНЫЙ ДОСТУП: необходимо выполнить некоторую работу перед ДОСТУПОМ, например, одновременные соединения и количество запросов в секунду должны быть ограничены, включая два модуля: limt_conn и limit_req.
  2. ДОСТУП: Основная проблема, которую необходимо решить, заключается в том, может ли пользователь получить доступ. Например, auth_basic — это имя пользователя и пароль, access — это IP-адрес доступа пользователя, а auth_request возвращает, можно ли получить к нему доступ в соответствии со сторонней службой.
  3. POST_ACCESS: что-то будет сделано после ACCESS, и модуль пока не будет использоваться.

Последние три этапа обрабатывают ответы и журналы:

  1. ПРЕДСОДЕРЖИМОЕ: перед обработкой СОДЕРЖИМОГО будут выполнены некоторые действия, например отправка подзапросов сторонним службам для обработки. Модуль try_files также находится на этом этапе.

  2. СОДЕРЖАНИЕ: На этом этапе задействовано множество модулей, таких как index, autoindex, concat и т. д. Все они вступают в силу на этом этапе.

  3. LOG: Запишите модуль access_log.

Вышеупомянутые этапы все обрабатываются в строгом порядке.Конечно, порядок обработки каждого HTTP-модуля на каждом этапе также очень важен.Если модуль не передает запрос вниз, последующие модули не получат запрос. Кроме того, не все модули на каждом этапе должны выполняться один раз, давайте поговорим о последовательности запросов между модулями на каждом этапе.

11 этапов последовательной обработки

Как показано на рисунке ниже, обработка каждого модуля упорядочена, так как же получить этот порядок? На самом деле все очень просто, в исходниках ngx_module.c есть массивngx_module_name, который содержит все модули, включенные в команду with при компиляции Nginx, порядок между ними очень важен, а порядок в массиве обратный.

char *ngx_module_names[] = {
    … …
    "ngx_http_static_module",
    "ngx_http_autoindex_module",
    "ngx_http_index_module",
    "ngx_http_random_index_module",
    "ngx_http_mirror_module",
    "ngx_http_try_files_module",
    "ngx_http_auth_request_module",
    "ngx_http_auth_basic_module",
    "ngx_http_access_module",
    "ngx_http_limit_conn_module",
    "ngx_http_limit_req_module",
    "ngx_http_realip_module",
    "ngx_http_referer_module",
    "ngx_http_rewrite_module",
    "ngx_http_concat_module",
    … …
}

Модули в серой части обрабатываются фреймворковой частью Nginx, а сторонние модули здесь не обрабатываются.

В процессе последовательного выполнения вниз он может не следовать этому порядку. Например, на этапе доступа есть инструкция под названием «удовлетворить», которая может дать указание перейти к следующему этапу для обработки, когда он будет удовлетворен, а затем выполнить модули auth_basic и auth_request.

На этапе содержимого, когда выполняется индексный модуль, модуль auto_index не будет выполняться, а будет напрямую переходить к модулю журнала.

Модули и последовательности, задействованные во всех 11 этапах, показаны на следующем рисунке:

Начнем с подробного объяснения каждого этапа. Давайте взглянем на первую стадию, стадию постпрочтения Как следует из названия, стадия постпрочтения работает до формальной обработки запроса.

постпрочитанная стадия

Этап postread — первый этап из 11. На этом этапе заголовок запроса только что получен, никакой обработки еще не производилось, мы можем получить некоторую исходную информацию. Например, получить реальный IP-адрес пользователя

Вопрос: Как узнать реальный IP-адрес пользователя?

Мы знаем, что TCP-соединение состоит из четырех кортежей, и в этот четырехкортеж входит исходный IP-адрес. В реальном интернете существует множество прямых прокси и обратных прокси. Например, у конечного пользователя есть свой IP-адрес в интрасети, оператор назначит публичный IP-адрес, и тогда при доступе к веб-сайту веб-сайт может использовать CDN для ускорения некоторых статических файлов или изображений.Если CDN не попадает, он будет return При возврате к источнику может потребоваться пройти через обратный прокси-сервер, такой как SLB Alibaba Cloud, прежде чем он достигнет Nginx.

Адрес, который мы хотим получить, должен быть общедоступным IP-адресом 115.204.33.1, назначенным оператором пользователю.Этот IP-адрес используется для контроля или ограничения одновременного соединения, но Nginx получает 2.2.2.2, так как мы можем его получить? реальный IP пользователя?

В протоколе HTTP есть два заголовка, которые можно использовать для получения IP-адреса пользователя:

  • X-Forwardex-For используется для передачи IP, этот заголовок будет записывать IP узла, который проходит через
  • X-Real-IP: может записывать реальный IP-адрес пользователя, может быть только один

Как им пользоваться после получения реального IP пользователя?

Для этой задачи используется Nginx на основе переменных.

Например, такие переменные, как binary_remote_addr и remote_addr, значением которых является реальный IP-адрес, поэтому ограничение на количество подключений — это модуль limit_conn.

Реалип модуль

  • Не компилируется в Nginx по умолчанию

    • нужно пройти--with-http_realip_moduleвключить функцию
  • Переменная: если вы все еще хотите использовать адрес и порт в исходном TCP-соединении, вам нужно сохранить его через эти две переменные.

    • realip_remote_addr
    • realip_remote_port
  • Функция

    • Изменить адрес клиента
  • инструкция

    • set_real_ip_from

      Укажите доверенный адрес, доверенным является только реалип, полученный от соединения, установленного с этого адреса

    • real_ip_header

      Укажите, из какого заголовка брать реальный IP-адрес, по умолчанию изX-Real-IPвзято, если установлено изX-Forwarded-ForВ середине он будет начинаться с последнего IP-адреса.

    • real_ip_recursive

      Loopback-адрес, закрытый по умолчанию, при открытии, еслиX-Forwarded-ForПоследний адрес совпадает с адресом клиента, который будет отфильтрован.

Syntax: set_real_ip_from address | CIDR | unix:;
Default: —
Context: http, server, location

Syntax: real_ip_header field | X-Real-IP | X-Forwarded-For | proxy_protocol;
Default: real_ip_header X-Real-IP; 
Context: http, server, location

Syntax: real_ip_recursive on | off;
Default: real_ip_recursive off; 
Context: http, server, location

настоящий бой

выше оreal_ip_recursiveИнструкции могут быть непростыми для понимания, давайте попрактикуемся, давайте сначала посмотримreal_ip_recursiveЗакрыто по умолчанию:

  • Перекомпилируйте nginx с модулем realip

Для получения подробной информации о том, как скомпилировать Nginx, см.:Я слово.GitHub.IO/2020/03/10/…

# 下载 nginx 源码,在源码目录下执行
./configure --prefix=自己指定的目录 --with-http_realip_module
make
make install
  • Затем перейдите в каталог установки Nginx, который вы указали на предыдущем шаге.
#屏蔽默认的 nginx.conf 文件的 server 块内容,并添加一行
include /Users/mtdp/myproject/nginx/test_nginx/conf/example/*.conf;
# 在 example 目录下建立 realip.conf,set_real_ip_from 可以设置为自己的本机 IP
server {
    listen 80;
    server_name ziyang.realip.com;
    error_log /Users/mtdp/myproject/nginx/nginx/logs/myerror.log debug;
    set_real_ip_from 192.168.0.108;
    #real_ip_header X-Real-IP;
    real_ip_recursive off;
    # real_ip_recursive on;
    real_ip_header X-Forwarded-For;

    location / {
        return 200 "Client real ip: $remote_addr\n";
    }
}

В приведенном выше файле конфигурации я установил доверенный адрес прокси-сервера в качестве локального адреса,real_ip_recursiveпо умолчанию выключено,real_ip_headerустановить изX-Forwarded-ForПринимать.

  • перезагрузить файл конфигурации
./sbin/nginx -s reload
  • Результаты тестового ответа
➜  test_nginx curl -H 'X-Forwarded-For: 1.1.1.1,192.168.0.108' ziyang.realip.com
Client real ip: 192.168.0.108

Затем снова проверьтеreal_ip_recursiveОткрытая ситуация:

  • открыть в конфигурационном файлеreal_ip_recursive
server {
    listen 80;
    server_name ziyang.realip.com;
    error_log /Users/mtdp/myproject/nginx/nginx/logs/myerror.log debug;
    set_real_ip_from 192.168.0.108;
    #real_ip_header X-Real-IP;
    #real_ip_recursive off;
    real_ip_recursive on;
    real_ip_header X-Forwarded-For;

    location / {
        return 200 "Client real ip: $remote_addr\n";
    }
}
  • Результаты тестового ответа
➜  test_nginx curl -H 'X-Forwarded-For: 1.1.1.1,2.2.2.2,192.168.0.108' ziyang.realip.com
Client real ip: 2.2.2.2

Так что здесь также можно увидеть, что если вы используетеX-Forwarded-ForЧтобы получить реалип, нужно открытьreal_ip_recursive, и, realip зависит отset_real_ip_fromУстановите доверенные адреса.

Тогда кто-то может спросить, просто используйтеX-Real-IPНехорошо выбирать настоящий IP-адрес. Это нормально, ноX-Real-IPОн уникален для Nginx, а не для спецификации RFC. Если между клиентом и сервером есть другие прокси-серверы, не относящиеся к Nginx, они будут недоступны.X-Real-IPГолова, так что это зависит от реальной ситуации.

Модуль перезаписи для этапа перезаписи

Давайте посмотрим на модуль перезаписи.

Прежде всего, этап перезаписи делится на два, один этап server_rewrite, а другой этап перезаписи.Оба этапа включают модуль перезаписи, а в модуле перезаписи есть команда возврата, которая не будет выполняться снова, когда это встречается команда. , верните ответ напрямую.

инструкция возврата

Синтаксис директивы return следующий:

  • Возвращает код состояния, за которым следует тело
  • Возвращает код состояния, за которым следует URL
  • Вернуть URL напрямую
Syntax: return code [text];
        return code URL;
        return URL;
Default: —
Context: server, location, if

Коды состояния возврата включают следующее:

  • Настройка Nginx
    • 444: Соединение немедленно закрывается, и пользователь не получает ответа.
  • Стандарт HTTP 1.0
    • 301: постоянное перенаправление
    • 302: Временная переадресация, запрещена к кешированию
  • Стандарт HTTP 1.1
    • 303: Временное перенаправление, изменение метода разрешено, кэширование запрещено.
    • 307: Временное перенаправление, изменение метода запрещено, кеширование запрещено
    • 308: Постоянное перенаправление, изменение метода запрещено.

директива возврата и error_page

error_pageРоль каждого надо часто видеть. Когда при посещении веб-сайта появляется ошибка 404, ошибка 404 НЕ НАЙДЕНА, как правило, появляется не напрямую, а на более дружественной странице, котораяerror_pageфункция.

Syntax: error_page code ... [=[response]] uri;
Default: —
Context: http, server, location, if in location

Давайте рассмотрим несколько примеров:

1. error_page 404 /404.html; 
2. error_page 500 502 503 504 /50x.html;
3. error_page 404 =200 /empty.gif; 
4. error_page 404 = /404.php; 
5. location / { 
       error_page 404 = @fallback; 
   } 
   location @fallback { 
       proxy_pass http://backend; 
   } 
6. error_page 403 http://example.com/forbidden.html; 
7. error_page 404 =301 http://example.com/notfound.html;

Итак, теперь будет две проблемы, давайте посмотрим на следующий файл конфигурации:

server {
    server_name ziyang.return.com;
    listen 80;
    root html/;
    error_page 404 /403.html;
    #return 405;
    location / {
        #return 404 "find nothing!";
    }
}
  1. Когда сервер содержит error_page и в локации есть инструкция возврата, какая из них будет выполнена?
  2. Директива return появляется одновременно и в блоке server, и в блоке location. Есть ли у них отношения слияния?

Давайте проверим эти две проблемы в реальном бою.

настоящий бой

  • Добавьте приведенную выше конфигурацию в файл конфигурации return.conf.
  • Привяжите ziyang.return.com к локальному IP-адресу в файле hosts этой машины.
  • посетить несуществующую страницу
➜  test_nginx curl  ziyang.return.com/text
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.17.8</center>
</body>
</html>

В это время вы можете видеть, чтоerror_pageЭто работает, и возвращается ответ 403.

то если открытьlocationВнизreturnКак насчет аннотаций к директивам?

  • ОткрытьreturnКомментарии к инструкции, перезагрузить файлы конфигурации
  • Вернуться на страницу
➜  test_nginx curl  ziyang.return.com/text
find nothing!%    

В этот момент,returnИнструкция была выполнена. Это первый вопрос, когдаserverсодержитerror_pageа такжеlocationподreturnКогда команда будет выполнена, она будет выполненаreturnинструкция.

Посмотрите нижеserverвнизreturnинструкция иlocationвнизreturnКакая команда будет выполняться.

  • ОткрытьserverВнизreturnКомментарии к директивам, перезагрузить файлы конфигурации
  • Вернуться на страницу
➜  test_nginx curl  ziyang.return.com/text
<html>
<head><title>405 Not Allowed</title></head>
<body>
<center><h1>405 Not Allowed</h1></center>
<hr><center>nginx/1.17.8</center>
</body>
</html>

На два вышеприведенных вопроса есть ответы:

  1. когдаserverсодержитerror_pageа такжеlocationподreturnКогда команда будет выполнена, какая из них будет выполнена?

    будет выполнятьlocationвнизreturnинструкция.

  2. returnКоманда также появляется вserverпод блоком и одновременноlocationПод блоком у них отношения слияния?

    Отношения слияния отсутствуют, какое из них встречается первымreturnКакая бы команда ни выполнялась первой.

переписать директиву

rewriteДирективы используются для изменения URL-адреса, который пользователи передают в Nginx. посмотриrewriteДирективные правила:

Syntax: rewrite regex replacement [flag];
Default: —
Context: server, location, if

Его основные функции заключаются в следующем:

  • будетregexУказанный URL заменяется наreplacementэтот новый URL
    • Может использовать регулярные выражения и извлечение переменных
  • когдаreplacementНачинается с http:// или https:// или $schema и возвращает прямое перенаправление 302
  • Заменяемый URL обрабатывается в соответствии с методом, указанным флагом
    • последний: использоватьreplacementэтот URL для нового совпадения местоположения
    • break: инструкция break останавливает выполнение текущей инструкции скрипта, что эквивалентно независимой инструкции break.
    • перенаправление: возвращает перенаправление 302
    • постоянный: возвращает перенаправление 301

Пример инструкции

Теперь у нас есть такая структура каталогов:

html/first/
└── 1.txt
html/second/
└── 2.txt
html/third/
└── 3.txt

Файл конфигурации выглядит следующим образом:

server {
    listen 80;
    server_name rewrite.ziyang.com;
    rewrite_log on;
    error_log logs/rewrite_error.log notice;

    root html/;
    location /first {
        rewrite /first(.*) /second$1 last;
        return 200 'first!\n';
    }

    location /second {
        rewrite /second(.*) /third$1;
        return 200 'second!\n';
    }

    location /third {
        return 200 'third!\n';
    }
    location /redirect1 {
        rewrite /redirect1(.*) $1 permanent;
    }

    location /redirect2 {
        rewrite /redirect2(.*) $1 redirect;
    }

    location /redirect3 {
        rewrite /redirect3(.*) http://rewrite.ziyang.com$1;
    }

    location /redirect4 {
        rewrite /redirect4(.*) http://rewrite.ziyang.com$1 permanent;
    }
} 

Итак, наш вопрос:

  1. Каков порядок инструкции возврата и инструкции перезаписи?
  2. Что возвращают посещения /first/3.txt, /second/3.txt и / Third/3.txt?
  3. Что делать, если вы не несете флаг?

С этими тремя вопросами, давайте на самом деле продемонстрируем это.

настоящий бой

Готов к работе

  • Добавьте приведенную выше конфигурацию в файл конфигурации rewrite.conf.
  • Привяжите rewrite.ziyang.com к 127.0.0.1 в файле hosts этой машины.

last flag

Сначала посетите rewrite.ziyang.com/first/3.txt, результаты следующие:

➜  ~ curl rewrite.ziyang.com/first/3.txt
second!

Почему результат второй?! Должна быть третья!Ага, может у кого-то возникнет такой вопрос. Фактические этапы сопоставления следующие:

  • curl rewrite.ziyang.com/first/3.txt
  • из-заrewrite /first(.*) /second$1 last;Существование этой директивы last означает использование нового URL-адреса для сопоставления местоположения, поэтому следующим шагом будет сопоставление second/3.txt.
  • После сопоставления с блоком /second инструкции будут выполняться последовательно и, наконец, вернут 200.
  • Обратите внимание, что хотя URL-адрес также переписывается в блоке местоположения, он не будет продолжать совпадать, поскольку позже не будет указан флаг.

break flag

Следующее будетrewrite /second(.*) /third$1;Эта инструкция плюс флаг прерывания,rewrite /second(.*) /third$1 break;

Продолжайте посещать rewrite.ziyang.com/first/3.txt, результаты следующие:

➜  ~ curl rewrite.ziyang.com/first/3.txt
test3%

В это время возвращается содержимое файла 3.txt test3. Фактические этапы сопоставления следующие:

  • curl rewrite.ziyang.com/first/3.txt
  • из-заrewrite /first(.*) /second$1 last;Существование этой директивы last означает использование нового URL-адреса для сопоставления местоположения, поэтому следующим шагом будет сопоставление second/3.txt.
  • После сопоставления блока /second из-за наличия флага разрыва он будет продолжать соответствовать URL-адресу после перезаписи.
  • соответствует /третье местоположение

Таким образом, фактически запрошенный этим процессом URL-адрес — rewrite.ziyang.com/ Third/3.txt, поэтому естественным результатом будет test3. Вы также можете попробовать посетить rewrite.ziyang.com/ Third/2.txt, чтобы узнать, что возвращается.

перенаправление и постоянный флаг

В конфигурационном файле тоже есть 4 локации, можете попробовать обратиться к ним по отдельности, результат такой:

  • перенаправление1: возвращает 301
  • перенаправление2: возвращает 302
  • перенаправление3: вернуть 302
  • перенаправление4: возвращает 301

rewriteжурнал поведения

В основном командаrewrite_log:

Syntax: rewrite_log on | off;
Default: rewrite_log off; 
Context: http, server, location, if

После включения этой команды лог перезаписи будет записываться в лог-файл logs/rewrite_error.log, который является лог-записью запроса /first/3.txt:

2020/05/06 06:24:05 [notice] 86959#0: *25 "/first(.*)" matches "/first/3.txt", client: 127.0.0.1, server: rewrite.ziyang.com, request: "GET /first/3.txt HTTP/1.1", host: "rewrite.ziyang.com"
2020/05/06 06:24:05 [notice] 86959#0: *25 rewritten data: "/second/3.txt", args: "", client: 127.0.0.1, server: rewrite.ziyang.com, request: "GET /first/3.txt HTTP/1.1", host: "rewrite.ziyang.com"
2020/05/06 06:24:05 [notice] 86959#0: *25 "/second(.*)" matches "/second/3.txt", client: 127.0.0.1, server: rewrite.ziyang.com, request: "GET /first/3.txt HTTP/1.1", host: "rewrite.ziyang.com"
2020/05/06 06:24:05 [notice] 86959#0: *25 rewritten data: "/third/3.txt", args: "", client: 127.0.0.1, server: rewrite.ziyang.com, request: "GET /first/3.txt HTTP/1.1", host: "rewrite.ziyang.com"

если директива

Директива if также действует на этапе перезаписи, и ее синтаксис выглядит следующим образом:

Syntax: if (condition) { ... }
Default: —
Context: server, location

Его правила таковы:

  • Если условие условие истинно, инструкция в фигурных скобках выполняется; она также следует правилам наследования для инструкций значения (подробности см. в моей предыдущей статье)Директивы конфигурации Nginx)

Так что же содержит условное выражение инструкции if? Его правила таковы:

  1. Проверьте, пуста ли переменная или значение равно 0
  2. Чтобы сопоставить переменные со строками, используйте = или !=
  3. Сопоставьте переменные с регулярными выражениями
    • С учетом регистра, ~ или!~
    • без учета регистра,* или !*
  4. Чтобы проверить, существует ли файл, используйте -f или !-f
  5. Чтобы проверить, существует ли каталог, используйте -d или !-d
  6. Проверьте, существуют ли файлы, каталоги, программные ссылки, используйте -e или !-e
  7. Чтобы проверить, является ли он исполняемым, используйте -x или !-x

Вот некоторые примеры:

if ($http_user_agent ~ MSIE) { # 与变量 http_user_agent 匹配
    rewrite ^(.*)$ /msie/$1 break; 
} 
if ($http_cookie ~* "id=([^;]+)(?:;|$)") { # 与变量 http_cookie 匹配
    set $id $1; 
} 
if ($request_method = POST) { # 与变量 request_method 匹配,获取请求方法
    return 405; 
} 
if ($slow) { # slow 变量在 map 模块中自定义,也可以进行匹配
    limit_rate 10k; 
} 
if ($invalid_referer) { 
    return 403; 
}

стадия find_config

После прохождения модуля перезаписи и сопоставления URL-адреса он перейдет на этап find_config и начнет поиск конфигурации местоположения, соответствующей URL-адресу.

директива о местоположении

синтаксис команды

Или старые правила, давайте сначала посмотрим на синтаксис директивы location:

Syntax: location [ = | ~ | ~* | ^~ ] uri { ... }
        location @name { ... }
Default: —
Context: server, location

Syntax: merge_slashes on | off;
Default: merge_slashes on; 
Context: http, server

Eстьmerge_slashesДиректива, функция этой директивы заключается в том, что если в добавленном URL-адресе есть два повторяющихся /, они будут объединены в один.Эта директива включена по умолчанию, и ее нужно закрывать только тогда, когда URL-адрес закодирован с помощью base64 или подобного .

правила сопоставления

Правило сопоставления для местоположения заключается в сопоставлении только URI и игнорировании параметров. Существует три основных случая:

  • строка префикса
    • обычный матч
    • =: точное совпадение
    • ^~: после сопоставления сопоставление регулярных выражений больше не выполняется.
  • регулярное выражение
    • ~: обычное соответствие с учетом регистра
    • ~*: без учета регистра
  • Именованное место внутреннего прыжка пользователя
    • @

Эти правила должны сначала показаться очень запутанными, и я не знаю, о чем они говорят Давайте рассмотрим несколько примеров из реального боя.

настоящий бой

Давайте посмотрим на файл конфигурации Nginx:

server {
    listen 80;
    server_name location.ziyang.com;
    error_log  logs/error.log  debug;
    #root html/;
    default_type text/plain;
    merge_slashes off;

    location ~ /Test1/$ {
        return 200 'first regular expressions match!\n';
    }
    location ~* /Test1/(\w+)$ {
        return 200 'longest regular expressions match!\n';
    }
    location ^~ /Test1/ {
        return 200 'stop regular expressions match!\n';
    }
    location /Test1/Test2 {
        return 200 'longest prefix string match!\n';
    }
    location /Test1 {
        return 200 'prefix string match!\n';
    }
    location = /Test1 {
        return 200 'exact match!\n';
    }
}

Вопрос в том, какой контент будет возвращен при посещении следующих URL-адресов?

/Test1
/Test1/
/Test1/Test2
/Test1/Test2/
/test1/Test2

Например, при доступе к /Test1 совпадут несколько частей:

  1. Обычное совпадение префикса: location /Test1
  2. Точное совпадение: location = /Test1

При доступе к /Test1/ также есть несколько частичных совпадений:

  1. location ~ /Test1/$
  2. location ^~ /Test1/

Так какой из них будет соответствовать? Nginx фактически следует набору правил, как показано на следующем рисунке:

Все строки префиксов помещаются в бинарное дерево, и Nginx будет разделен на две части для сопоставления:

  1. Сначала просмотрите все строки префикса и выберите самую длинную строку префикса. Если эта строка является точным совпадением = или совпадением префикса ^~, она будет использоваться напрямую.
  2. Если на первом шаге нет совпадения = или ^~, то сначала будет запомнено самое длинное совпадающее расположение строки префикса.
  3. Сопоставьте регулярные выражения по порядку в соответствии с конфигурацией в файле nginx.conf.
  4. Если ни одно из регулярных выражений не соответствует, будет использоваться самая длинная совпадающая строка префикса.

Вот как выглядит фактический ответ:

➜  test_nginx curl location.ziyang.com/Test1
exact match!
➜  test_nginx curl location.ziyang.com/Test1/
stop regular expressions match!
➜  test_nginx curl location.ziyang.com/Test1/Test2
longest regular expressions match!
➜  test_nginx curl location.ziyang.com/Test1/Test2/
longest prefix string match!
➜  test_nginx curl location.ziyang.com/Test1/Test3
stop regular expressions match!
  • /Test1 соответствует местоположению = /Test1
  • /Test1/ соответствует местоположению ^~ /Test1/
  • /Test1/Test2 соответствует местоположению ~* /Test1/(\w+)$
  • /Test1/Test2/ соответствует местоположению /Test1/Test2
  • /Test1/Test3 соответствует местоположению ^~ /Test1/

Здесь мы сосредоточимся на объяснении процесса сопоставления /Test1/Test3:

  1. Пройдите все строки префиксов, которые могут быть сопоставлены, всего их две.
    • ^~ /Test1/
    • /Test1
  2. Выберите самую длинную строку префикса /Test1/, потому что перед ней стоит ^~, чтобы запретить сопоставление с регулярным выражением, поэтому напрямую используйте правила расположения ^~ /Test1/
  3. вернутьstop regular expressions match!

этап предварительного доступа

Теперь наступает этап предварительного доступа. Мы часто сталкиваемся с проблемой, то есть как ограничить количество одновременных подключений на одного клиента? Как ограничить частоту доступа? Они обрабатываются на этапе предварительного доступа, который, как следует из названия, предшествует соединению. Давайте сначала посмотрим на модуль limit_conn.

модуль limit_conn

Здесь задействованы модулиngx_http_limit_conn_module, его основные характеристики следующие:

  • Эффективная стадия:NGX_HTTP_PREACCESS_PHASEсцена
  • Модуль:http_limit_conn_module
  • Компилируется в Nginx по умолчанию через--without-http_limit_conn_moduleинвалид
  • Рабочий диапазон
    • Все рабочие процессы (на основе общей памяти)
    • Не вступает в силу до входа в стадию предварительного доступа
    • Срок действия ограничения зависит от дизайна ключа: полагайтесь на модуль realip на этапе постчтения, чтобы получить настоящий IP-адрес.

Здесь следует отметить конструкцию ключа limit_conn.Так называемый ключ относится к тому, какая переменная ограничена.Обычно мы берем реальный IP-адрес пользователя.

После разговора о модуле limit_conn давайте поговорим о синтаксисе команды.

синтаксис команды

  • Определите общую память (включая размер) и ключевое слово
Syntax: limit_conn_zone key zone=name:size;
Default: —
Context: http
  • Ограничьте количество одновременных подключений
Syntax: limit_conn zone number;
Default: —
Context: http, server, location
  • Уровень журнала, на котором происходит регулирование
Syntax: limit_conn_log_level info | notice | warn | error;
Default: limit_conn_log_level error; 
Context: http, server, location
  • Код ошибки, возвращаемый клиенту при превышении лимита
Syntax: limit_conn_status code;
Default: limit_conn_status 503; 
Context: http, server, location

настоящий бой

Теперь пришло время для настоящего боя Давайте посмотрим, как работают приведенные выше команды на реальном примере.

Старые правила, сначала в конфигурационном файле:

limit_conn_zone $binary_remote_addr zone=addr:10m;
#limit_req_zone $binary_remote_addr zone=one:10m rate=2r/m;

server {
    listen 80;
    server_name limit.ziyang.com;
    root html/;
    error_log logs/myerror.log info;
    location /{
        limit_conn_status 500;
        limit_conn_log_level  warn;
        limit_rate 50;
        limit_conn addr 1;
        #limit_req zone=one burst=3 nodelay;
        #limit_req zone=one;
    }
}
  • Добавьте limit.ziyang.com в качестве локального IP-адреса в файл локальных хостов.

В этом конфигурационном файле сделаны два ограничения, одноlimit_rateограничение до 50 байт, одновременные соединенияlimit_connОграничение равно 1.

➜  test_nginx curl limit.ziyang.com

В настоящее время, если вы посетите сайт limit.ziyang.com, вы обнаружите, что скорость очень низкая, потому что всего 50 байт в секунду.

Если вы снова зайдете на сайт в то же время, он вернет 500.

Я получаю доступ одновременно в другом терминале:

➜  ~ curl limit.ziyang.com
<html>
<head><title>500 Internal Server Error</title></head>
<body>
<center><h1>500 Internal Server Error</h1></center>
<hr><center>nginx/1.17.8</center>
</body>
</html>

Как видите, Nginx напрямую вернул 500.

модуль limit_req

Мы начали этот раздел с двух вопросов:

  • Как ограничить количество одновременных подключений на одного клиента?

  • Как ограничить частоту доступа?

Первая проблема ограничения количества одновременных подключений решена, давайте рассмотрим вторую проблему.

Действующие модули здесьngx_http_limit_req_module, его основные характеристики следующие:

  • Эффективная стадия:NGX_HTTP_PREACCESS_PHASEсцена
  • Модуль:http_limit_req_module
  • Компилируется в Nginx по умолчанию через--without-http_limit_req_moduleинвалид
  • Эффективный алгоритм: алгоритм дырявого ведра
  • Рабочий диапазон
    • Все рабочие процессы (на основе общей памяти)
    • Не вступает в силу до входа в стадию предварительного доступа

алгоритм дырявого ведра

Алгоритм дырявого ведра называется алгоритмом дырявого ведра.К другим алгоритмам, используемым для ограничения частоты запросов, относятся алгоритм Token Ring и т. д., которые здесь обсуждаться не будут.

Принцип алгоритма дырявого ведра заключается в том, чтобы сначала определить размер ведра, и все запросы, поступающие в ведро, будут обрабатываться с постоянной скоростью.Если слишком много запросов превысит вместимость ведра, будет немедленно возвращена ошибка. Объясните картинкой.

На этой картинке кран капает непрерывно, как и запрос, отправленный пользователем, все капли воды будут вытекать с постоянной скоростью, то есть они будут обработаны. Алгоритм дырявого ведра хорошо ограничивает пакетный трафик и будет гладко обрабатывать все запросы.

синтаксис команды

  • Определите общую память (включая размер), а также ключевые слова и ограничение скорости
Syntax: limit_req_zone key zone=name:size rate=rate ;
Default: —
Context: http

Единицей скорости является r/s или r/m (сколько запросов обрабатывается в минуту или в секунду).

  • Ограничьте количество одновременных подключений
Syntax: limit_req zone=name [burst=number] [nodelay];
Default: —
Context: http, server, location
  • взрыв по умолчанию равен 0
  • nodelay, если этот параметр установлен, то запрос в дырявое ведро тоже сразу вернет ошибку
  • Уровень журнала, на котором происходит регулирование
Syntax: limit_req_log_level info | notice | warn | error;
Default: limit_req_log_level error; 
Context: http, server, location
  • Код ошибки, возвращаемый клиенту при превышении лимита
Syntax: limit_req_status code;
Default: limit_req_status 503; 
Context: http, server, location

настоящий бой

Перед фактической проверкой необходимо обратить внимание на два вопроса:

  • Когда конфигурации limit_req и limit_conn вступают в силу одновременно, что имеет более высокий приоритет?
  • добавлен нодлай или нет, в чем разница?

Добавьте файл конфигурации.Этот файл конфигурации фактически такой же, как файл конфигурации в предыдущем разделе, но его необходимо прокомментировать:

limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_req_zone $binary_remote_addr zone=one:10m rate=2r/m;

server {
    listen 80;
    server_name limit.ziyang.com;
    root html/;
    error_log logs/myerror.log info;

    location /{
        limit_conn_status 500;
        limit_conn_log_level  warn;
        #limit_rate 50;
        #limit_conn addr 1;
        #limit_req zone=one burst=3 nodelay;
        limit_req zone=one;
    }
}

Вывод: вlimit_req zone=oneПо команде 503 будет возвращено сразу после превышения количества запросов, обработанных в минуту.

➜  test_nginx curl limit.ziyang.com
<html>
<head><title>503 Service Temporarily Unavailable</title></head>
<body>
<center><h1>503 Service Temporarily Unavailable</h1></center>
<hr><center>nginx/1.17.8</center>
</body>
</html>

Измените закомментированную команду:

limit_req zone=one burst=3;
#limit_req zone=one;

Если пакетный параметр не добавлен, ошибка будет возвращена немедленно, а после его добавления ошибка не будет возвращена, а будет ждать снятия ограничения запроса, пока запрос не будет обработан, прежде чем вернуться.

Давайте посмотрим на параметр nodelay:

limit_req zone=one burst=3 nodelay;

После добавления nodelay запросы могут обрабатываться и возвращаться непосредственно перед достижением лимита пакетов, а 503 будет возвращено только после превышения лимита пакетов.

Пришло время ответить на два вопроса, поставленных в начале:

  • Когда конфигурации limit_req и limit_conn вступают в силу одновременно, что имеет более высокий приоритет?
    • limit_req обрабатывается до limit_conn, поэтому limit_req вступит в силу
  • добавлен нодлай или нет, в чем разница?
    • Без nodelay запрос будет ждать, пока запрос не будет обработан; с nodelay он будет обработан и немедленно возвращен, если предел пакета не превышен, и 503 будет возвращен, если предел превышен.

этап доступа

После ограничения пользователя на этапе предварительного доступа наступает фаза доступа.

модуль доступа

Здесь задействованы модулиngx_http_access_module, его основные характеристики следующие:

  • Эффективная стадия:NGX_HTTP_ACCESS_PHASEсцена
  • Модуль:http_access_module
  • Компилируется в Nginx по умолчанию через--without-http_access_moduleинвалид
  • Рабочий диапазон
    • Не вступает в силу до входа в фазу доступа

синтаксис команды

Syntax: allow address | CIDR | unix: | all;
Default: —
Context: http, server, location, limit_except

Syntax: deny address | CIDR | unix: | all;
Default: —
Context: http, server, location, limit_except

Модуль доступа предоставляет две инструкцииallowа такжеdeny, чтобы увидеть несколько примеров:

location / { 
    deny 192.168.1.1; 
    allow 192.168.1.0/24; 
    allow 10.1.1.0/16; 
    allow 2001:0db8::/32; 
    deny all; 
}

Для пользовательского доступа эти инструкции выполняются последовательно, и когда одна из них удовлетворена, она не будет выполняться дальше. Этот модуль относительно прост, и мы не будем делать здесь практические упражнения.

модуль auth_basic

Модуль auth_basic используется для аутентификации пользователя. Когда этот модуль включен, когда мы заходим на сайт через браузер, он возвращает 401 Unauthorized. Конечно, пользователь 401 этого не увидит, и в браузере появится диалоговое окно. окно с запросом имени пользователя и пароля. Этот модуль использует определение в RFC2617.

синтаксис команды

  • Аутентификация по паролю пользователя на основе протокола базовой аутентификации HTTP
  • Компилируется в Nginx по умолчанию
    • --without-http_auth_basic_module
    • disable ngx_http_auth_basic_module
Syntax: auth_basic string | off;
Default: auth_basic off; 
Context: http, server, location, limit_except

Syntax: auth_basic_user_file file;
Default: —
Context: http, server, location, limit_except

Здесь мы будем использовать инструмент под названием htpasswd, который можно использовать для создания файла паролей, иauth_basic_user_fileПросто положитесь на этот файл паролей.

htpasswd зависит от установочного пакета httpd-tools

Команда для генерации пароля:

htpasswd –c file –b user pass

Формат сгенерированного файла паролей:

# comment 
name1:password1 
name2:password2:comment 
name3:password3

настоящий бой

  • Создайте файл паролей auth.pass в каталоге примера
htpasswd -bc auth.pass ziyang 123456
  • Добавить файл конфигурации
server {
    server_name access.ziyang.com;
    listen 80;
    error_log  logs/error.log  debug;
    default_type text/plain;
    location /auth_basic {
        satisfy any;
        auth_basic "test auth_basic";
        auth_basic_user_file example/auth.pass;
        deny all;
    }
}
  • Перезагрузите файл конфигурации Nginx
  • Добавьте access.ziyang.com в файл /etc/hosts

В это время при посещении access.ziyang.com появится диалоговое окно с предложением ввести пароль:

модуль auth_request

  • Функция: перенаправить запрос вышестоящей службе, если код ответа, возвращенный вышестоящей службой, равен 2xx, продолжить выполнение, если код ответа, возвращенный вышестоящей службой, равен 2xx, продолжить выполнение, если вышестоящая служба возвращает 401 или 403. , он ответит возврат клиенту
  • Принцип: после получения запроса сгенерируйте подзапрос и передайте запрос вышестоящей службе через технологию обратного прокси.
  • Он не скомпилирован в Nginx по умолчанию, его нужно скомпилировать через --with-http_auth_request_module

синтаксис команды

Syntax: auth_request uri | off;
Default: auth_request off; 
Context: http, server, location

Syntax: auth_request_set $variable value;
Default: —
Context: http, server, location

настоящий бой

  • Добавьте следующее в предыдущий файл конфигурации
server {
    server_name access.ziyang.com;
    listen 80;
    error_log  logs/error.log  debug;
    #root html/;
    default_type text/plain;
    location /auth_basic {
        satisfy any;
        auth_basic "test auth_basic";
        auth_basic_user_file example/auth.pass;
        deny all;
    }
    location / {
        auth_request /test_auth;
    }
    location = /test_auth {
        proxy_pass http://127.0.0.1:8090/auth_upstream;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header X-Original-URI $request_uri;
    }
}
  • В этом файле конфигурации запрос будет перенаправлен на другую службу по пути /, и вы можете использовать nginx для создания другой службы.
  • Если служба возвращает 2xx, аутентификация прошла успешно, если она возвращает 401 или 403, аутентификация не удалась.

удовлетворять директиве, ограничивающей все модули фазы доступа

синтаксис команды

Syntax: satisfy all | any;
Default: satisfy all; 
Context: http, server, location

satisfyИнструкция имеет два значения, одно все, а другое любое.Этот модуль действителен для всех трех модулей на этапе доступа:

  • модуль доступа
  • модуль auth_basic
  • модуль auth_request
  • другие модули

еслиsatisfyЕсли значение инструкции равно all, это означает, что все модули в стадии доступа должны быть выполнены, и они будут освобождены только в случае их прохождения; если значение равно any, это означает, что любой модуль может быть выполнен.

Вот несколько вопросов, чтобы углубить ваше понимание:

  1. Если есть директива возврата, вступит ли в силу фаза доступа?

    Директива return относится к фазе перезаписи, предшествующей фазе доступа, поэтому она не вступит в силу.

  2. Имеет ли значение порядок множественных модулей доступа?

    ngx_http_auth_request_module,
    ngx_http_auth_basic_module,
    ngx_http_access_module,

    влиятельный

  3. Введите правильный пароль, могу ли я получить доступ к файлу ниже?

    location /{
        satisfy any;
        auth_basic "test auth_basic";
        auth_basic_user_file examples/auth.pass;
        deny all;
    }

    доступный, потому чтоsatisfyЗначение любое, поэтому, пока модуль удовлетворяет этому требованию, его можно освободить.

  4. Что, если вы поставите deny all перед auth_basic?

    Это все еще возможно, потому что порядок выполнения каждого модуля не имеет ничего общего с порядком инструкций.

  5. Если поменять на разрешить всем, есть ли возможность ввести пароль?

    Никаких шансов, потому что allow all — это модуль доступа, выполняемый перед модулем auth_basic.

стадия предварительного содержания

Сказав это, давайте рассмотрим 11 этапов обработки HTTP-запросов Nginx:

Теперь мы подошли к этапу преконтента, в котором есть только директива try_files.

модуль try_files

синтаксис команды

Syntax: try_files file ... uri;
        try_files file ... =code;
Default: —
Context: server, location
  • Модуль:ngx_http_try_files_moduleмодуль
  • Попробуйте получить доступ к файлам, соответствующим нескольким URL-адресам (указанным директивой root или alias) по очереди. Если файл существует, он возвращает содержимое файла напрямую. Если все файлы не существуют, он возвращается в соответствии с последним результатом или кодом URL.

настоящий бой

Давайте на самом деле посмотрим на пример:

server {
    server_name tryfiles.ziyang.com;
    listen 80;
    error_log  logs/myerror.log  info;
    root html/;
    default_type text/plain;
    location /first {
        try_files /system/maintenance.html
            $uri $uri/index.html $uri.html
            @lasturl;
    }
    location @lasturl {
        return 200 'lasturl!\n';
    }
    location /second {
        try_files $uri $uri/index.html $uri.html =404;
    }
}

Результат выглядит следующим образом:

  • Посещение /first фактически переходит к lasturl, а затем возвращает 200
  • Доступ к /second возвращает 404

Оба результата согласуются с файлом конфигурации.

➜  test_nginx curl tryfiles.ziyang.com/second
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.17.8</center>
</body>
</html>
➜  test_nginx curl tryfiles.ziyang.com/first 
lasturl!

зеркальный модуль

Зеркальный модуль может копировать трафик в режиме реального времени, что очень полезно для запросов, которым требуется одновременный доступ к нескольким средам.

синтаксис команды

  • Модуль:ngx_http_mirror_moduleМодуль, скомпилированный в Nginx по умолчанию
    • Удалите модуль через --without-http_mirror_module
  • Функция: при обработке запроса генерировать подзапрос для доступа к другим службам и не обрабатывать возвращаемое значение подзапроса.
Syntax: mirror uri | off;
Default: mirror off; 
Context: http, server, location

Syntax: mirror_request_body on | off;
Default: mirror_request_body on; 
Context: http, server, location

настоящий бой

  • Файл конфигурации выглядит следующим образом, вам нужно открыть другой Nginx, чтобы получить запрос
server {
    server_name mirror.ziyang.com;
    listen 8001;
    error_log logs/error_log debug;
    location / {
        mirror /mirror;
        mirror_request_body off;
    }
    location = /mirror {
        internal;
        proxy_pass http://127.0.0.1:10020$request_uri;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header X-Original-URI $request_uri;
    }
}
  • Журнал запросов можно посмотреть в файле access.log

этап содержания

Давайте начнем с этапа контента. Давайте сначала посмотрим на статический модуль на этапе контента. Хотя это последний модуль обработки на этапе контента, давайте представим его первым.

статический модуль

директивы root и alias

Давайте взглянем на две директивы root и alias, обе из которых используются для сопоставления путей к файлам.

Syntax: alias path;
Default: —
Context: location
Syntax: root path;
Default: root html; 
Context: http, server, location, if in location
  • Функция: сопоставление URL-адреса с путем к файлу для возврата статического содержимого файла.
  • Разница: root сопоставит полный URL-адрес с путем к файлу, псевдоним сопоставит только URL-адрес после местоположения с путем к файлу.

настоящий бой

Вот вопрос:

Теперь есть путь к файлу:

html/first/
└── 1.txt

Файл конфигурации выглядит следующим образом:

server {
    server_name static.ziyang.com;
    listen 80;
    error_log  logs/myerror.log  info;
    location /root {
        root html;
    }
    location /alias {
        alias html;
    }
    location ~ /root/(\w+\.txt) {
        root html/first/$1;
    }
    location ~ /alias/(\w+\.txt) {
        alias html/first/$1;
    }
    location  /RealPath/ {
        alias html/realpath/;
        return 200 '$request_filename:$document_root:$realpath_root\n';
    }
}

Итак, какой ответ вы получаете при посещении следующего URL-адреса?

/root
/alias
/root/1.txt
/alias/1.txt
➜  test_nginx curl static.ziyang.com/alias/1.txt
test1%
➜  test_nginx curl static.ziyang.com/alias/     
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
➜  test_nginx curl static.ziyang.com/root/      
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.17.8</center>
</body>
</html>
➜  test_nginx curl static.ziyang.com/root/1.txt
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.17.8</center>
</body>
</html>

Результаты, полученные при доступе к этим четырем путям:

  • / корень: 404
  • /псевдоним: 200
  • /корень/1.txt:404
  • /псевдоним/1.txt:200

Почему это? Это связано с тем, что когда корень сопоставляет URL-адрес, также будет добавлен путь в местоположении, то есть:

  • static.ziyang.com/root/Фактический визит являетсяhtml/root/
  • static.ziyang.com/root/1.txtФактическиhtml/first/1.txt/root/1.txt
  • static.ziyang.com/alias/на самом деле доступ правильноhtmlпапка, так как есть/существует, поэтому фактический доступhtml/index.html
  • static.ziyang.com/alias/1.txtФактический визит являетсяhtml/first/1.txt, файл существует

три коррелированные переменные

Или приведенный выше файл конфигурации:

location  /RealPath/ {
    alias html/realpath/;
    return 200 '$request_filename:$document_root:$realpath_root\n';
}

Здесь проблема с доступом/RealPath/1.txtКаковы значения этих трех переменных?

Чтобы ответить на этот вопрос, давайте сначала объясним три переменные:

  • request_filename: полный путь к файлу, к которому нужно получить доступ
  • document_root: путь к папке, сгенерированный директивами URI и root/alias (может содержать пути символических ссылок)
  • realpath_root: заменить программные ссылки в document_root реальными путями.

Чтобы проверить эти три переменные, создайте программную ссылку в каталоге html, указывающую на первую папку:

ln -s first realpath
➜  html curl static.ziyang.com/realpath/1.txt
/Users/mtdp/myproject/nginx/test_nginx/html/realpath/1.txt:/Users/mtdp/myproject/nginx/test_nginx/html/realpath/:/Users/mtdp/myproject/nginx/test_nginx/html/first

Видно, что есть три пути:

  • /Users/mtdp/myproject/nginx/test_nginx/html/realpath/1.txt
  • /Users/mtdp/myproject/nginx/test_nginx/html/realpath/
  • /Users/mtdp/myproject/nginx/test_nginx/html/first

Существуют и другие директивы конфигурации, такие как:

Content-Type при возврате статических файлов

Syntax: types { ... }
Default: types { text/html html; image/gif gif; image/jpeg jpg; } 
Context: http, server, location

Syntax: default_type mime-type;
Default: default_type text/plain; 
Context: http, server, location

Syntax: types_hash_bucket_size size;
Default: types_hash_bucket_size 64; 
Context: http, server, location

Syntax: types_hash_max_size size;
Default: types_hash_max_size 1024; 
Context: http, server, location

Журнал ошибок, когда файл не найден

Syntax: log_not_found on | off;
Default: log_not_found on; 
Context: http, server, location

В производственной среде часто могут быть случаи, когда файл не может быть найден, и журнал ошибок будет распечатан:

[error] 10156#0: *10723 open() "/html/first/2.txt/root/2.txt" failed (2: No such file or directory)

Если вы не хотите вести журнал, вы можете отключить его.

перенаправленное доменное имя

Теперь есть другая проблема, когда мы заходим в каталог, не заканчивая/, статический модуль вернет перенаправление 301, так как же определяется это правило? Посмотрите на следующие три инструкции:

# 该指令决定重定向时的域名,可以决定返回哪个域名
Syntax: server_name_in_redirect on | off;
Default: server_name_in_redirect off; 
Context: http, server, location
# 该指令决定重定向时的端口
Syntax: port_in_redirect on | off;
Default: port_in_redirect on; 
Context: http, server, location
# 该指令决定是否填域名,默认是打开的,也就是返回绝对路径
Syntax: absolute_redirect on | off;
Default: absolute_redirect on; 
Context: http, server, location

Чтобы продемонстрировать фактическое использование этих трех команд, давайте сначала посмотрим на файл конфигурации:

server {
    server_name return.ziyang.com dir.ziyang.com;
    server_name_in_redirect on;
    listen 8088;
    port_in_redirect on;
    absolute_redirect off;

    root html/;
}

absolute_redirectОн включен по умолчанию, отключаем и смотрим, как он возвращается:

➜  test_nginx curl localhost:8088/first -I
HTTP/1.1 301 Moved Permanently
Server: nginx/1.17.8
Date: Tue, 12 May 2020 00:31:36 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: /first/

В это время см. возвращенный заголовокLocationДоменное имя не добавлено.

Следующийabsolute_redirectОткройте (он открыт по умолчанию, поэтому просто закомментируйте его) и посмотрите, что возвращается:

  • absolute_redirect on
  • server_name_in_redirect on
  • port_in_redirect on
➜  test_nginx curl localhost:8088/first -I
HTTP/1.1 301 Moved Permanently
Server: nginx/1.17.8
Date: Tue, 12 May 2020 00:35:49 GMT
Content-Type: text/html
Content-Length: 169
Location: http://return.ziyang.com:8088/first/
Connection: keep-alive

Видно, что в это время возвращается доменное имя, и возвращается основное доменное имя плюс номер порта, который мы настроили.Это потому, что,server_name_in_redirectа такжеport_in_redirectЭти две команды включены. Если вы отключите эти две команды, посмотрите, что возвращается:

  • absolute_redirect on

  • server_name_in_redirect off

  • port_in_redirect off

➜  test_nginx curl localhost:8088/first -I
HTTP/1.1 301 Moved Permanently
Server: nginx/1.17.8
Date: Tue, 12 May 2020 00:39:31 GMT
Content-Type: text/html
Content-Length: 169
Location: http://localhost/first/
Connection: keep-alive

Обе директивы настроены наoffПосле этого вы обнаружите, что это уже не основное доменное имя плюс номер порта, а доменное имя и номер порта, которые мы запросили.Если вы добавите заголовок запросаHost, то он будет использоватьHostИмя домена в заголовке запроса.

индексный модуль

  • Модуль:ngx_http_index_module

  • Функция: указать/При доступе к каталогу в конце возвращается содержимое индексного файла.

  • грамматика:

    Syntax: index file ...;
    Default: index index.html; 
    Context: http, server, location
  • Выполняется перед модулем автоиндексации

Этот модуль, когда мы обращаемся к/В конце каталога он найдет index.html в папке корневой или псевдонимной инструкции.Если есть этот файл, будет возвращено содержимое файла, а также могут быть указаны другие файлы.

модуль автоиндексации

  • Модуль:ngx_http_autoindex_module, скомпилированный в Nginx по умолчанию, используйте--without-http_autoindex_moduleОтмена

  • Функция: когда URL-адрес начинается с/В конце попробуйте вернуть структуру каталогов, указывающую на каталог в root/alias в формате html/xml/json/jsonp и т.д.

  • грамматика:

    # 开启或关闭
    Syntax: autoindex on | off;
    Default: autoindex off; 
    Context: http, server, location
    # 当以 HTML 格式输出时,控制是否转换为 KB/MB/GB
    Syntax: autoindex_exact_size on | off;
    Default: autoindex_exact_size on; 
    Context: http, server, location
    # 控制以哪种格式输出
    Syntax: autoindex_format html | xml | json | jsonp;
    Default: autoindex_format html; 
    Context: http, server, location
    # 控制是否以本地时间格式显示还是 UTC 格式
    Syntax: autoindex_localtime on | off;
    Default: autoindex_localtime off; 
    Context: http, server, location

настоящий бой

  • Файл конфигурации выглядит следующим образом:
server {
    server_name autoindex.ziyang.com;
    listen 8080;
    location / {
        alias html/;
        autoindex on;
        #index b.html;
        autoindex_exact_size on;
        autoindex_format html;
        autoindex_localtime on;
    }
}

Здесь я положилindex b.htmlЭта инструкция закомментирована, и индексный модуль компилируется в Nginx по умолчанию, а инструкция по умолчаниюindex index.html, поэтому он будет искать файл index.html.

  • Откройте браузер и посетите autoindex.ziyang.com: 8080. По умолчанию в каталоге html есть файл index.html, поэтому отображаемый результат:

  • Открытьindex b.htmlКомментарии к инструкции. Так как файла b.html в папке html нет, то запрос уйдет в модуль автоиндексации и отобразит директорию:

Следующий формат отображения размера файла задаетсяautoindex_exact_size on;определяется этой командой.

конкат модуль

Ниже представлен модуль, который может улучшить производительность небольших файлов.Этот модуль был разработан Alibaba и широко используется на Taobao.

  • Модуль: ngx_http_concat_module

  • Разработчик модуля: Tengine (GitHub.com/alibaba/что я… --add-module=../nginx-http-concat/

  • Функция: объединение нескольких запросов небольших файлов, что может значительно повысить производительность HTTP-запросов.

  • инструкция:

    #在 URI 后面加上 ??,通过 ”,“ 分割文件,如果还有参数,则在最后通过 ? 添加参数
    concat on | off
    default concat off
    Context http, server, location
    
    concat_types MIME types
    Default concat_types: text/css application/x-javascript
    Context http, server, location
    
    concat_unique on | off
    Default concat_unique on
    Context http, server, location
    
    concat_max_files numberp
    Default concat_max_files 10
    Context http, server, location
    
    concat_delimiter string
    Default NONE
    Context http, server, locatione
    concat_ignore_file_error on | off
    Default off
    Context http, server, location

Откройте домашнюю страницу Taobao, вы обнаружите, что благодаря этому модулю улучшена производительность всех небольших файлов:

Я не буду здесь заниматься настоящим боем. Желающие могут собрать этот модуль и провести некоторые эксперименты. Я помещаю файл конфигурации здесь:

server {
    server_name concat.ziyang.com;
    error_log logs/myerror.log debug;
    concat on;
    root html;
    location /concat {
        concat_max_files 20;
        concat_types text/plain;
        concat_unique on;
        concat_delimiter ':::';
        concat_ignore_file_error on;
    }
}

фаза регистрации

Следующее, наконец, подходит к последнему этапу из 11 этапов, модулю журнала, который записывает журнал запросов доступа.

  • Функция: запись информации, связанной с HTTP-запросом, в журнал.
  • Модуль:ngx_http_log_module, нельзя отключить

формат журнала доступа

Syntax: log_format name [escape=default|json|none] string ...;
Default: log_format combined "..."; 
Context: http

Комбинированный формат журнала по умолчанию:

log_format combined '$remote_addr - $remote_user [$time_local] ' 
'"$request" $status $body_bytes_sent ' '"$http_referer" 
"$http_user_agent"';

Настроить путь к файлу журнала

Syntax: access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
        access_log off;
Default: access_log logs/access.log combined; 
Context: http, server, location, if in location, limit_except
  • Путь может содержать переменные: когда кеш не открыт, каждый журнал нужно открывать и закрывать.

  • если контролировать, записывается ли журнал запросов через значение переменной

  • кеш журнала

    • Функция: Запись журналов в памяти на диск пакетами.

    • Условия записи на диск:

      Размер всех журналов для записи на диск превышает размер кэша;

      Достигнуто время истечения, указанное флешем;

      Рабочий процесс выполняет команду повторного открытия или завершает работу.

  • сжатие журнала

    • Функция: пакетное сжатие логов в памяти, а затем запись на диск
    • Размер буфера по умолчанию равен 64 КБ.
    • Уровень сжатия по умолчанию равен 1 (1 — самый быстрый с самой низкой степенью сжатия, 9 — самый медленный с самой высокой степенью сжатия).
    • Когда сжатие журнала включено, кэширование журнала включено по умолчанию.

Оптимизация, когда имена файлов журнала содержат переменные

Syntax: open_log_file_cache max=N [inactive=time] [min_uses=N] [valid=time];
        open_log_file_cache off;
Default: open_log_file_cache off; 
Context: http, server, location
  • max: максимальное количество файловых дескрипторов в кеше, после которого он будет устранен алгоритмом LRU
  • inactive: файл не будет закрыт в течение этого периода времени после доступа к файлу. По умолчанию 10 секунд
  • min_uses: он будет продолжать существовать в памяти, только если он используется больше, чем min_uses в течение неактивного времени. По умолчанию 1
  • действительный: по истечении действительного времени кэшированный файл журнала будет проверен на существование. По умолчанию 60 секунд
  • off: отключить функцию кеша

Модуль журнала не имеет реального боя.


На данный момент мы разобрались со всеми 11 этапами обработки HTTP-запросов Nginx, и каждый этап в основном имеет соответствующий модуль. Я считаю, что для такого полного анализа процесса каждый может понять конфигурацию Nginx, Кроме того, вы можете гибко настроить нужную конфигурацию в соответствии со своими потребностями, поэтому вы действительно можете освоить 11 этапов.

Наконец, приглашаю всех обратить внимание на мой личный блог:iziyang.github.io


Эта статья была впервые опубликована в моем личном блоге:iziyang.github.io