Используйте nginx для перезаписи uri и прокси-функций в среде разработки.

Nginx

Эта статья синхронизирована в личном блогеshymean.comвверх, добро пожаловать, чтобы следовать

В этой статье разбирается метод использования nginx для перезаписи uri и прокси-функций при фронтенд-разработке в среде разработки.

Ссылаться на

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

Ссылаться на

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

location [ = | ~ | ~* | ^~ ] uri { ... }

Между директивой местоположения и запросом uri можно добавить необязательные модификаторы. Значения четырех модификаторов следующие:

  • = означает точное совпадение. Он сработает только в том случае, если запрошенный URL-адрес точно равен следующей строке.

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

  • ~* Указывает, что правило определено с использованием регулярного выражения и не чувствительно к регистру.

  • ^~ означает, что если символ, следующий за символом, является наиболее подходящим, правило применяется, и последующие поиски не выполняются.

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

Следует отметить, что одни и те же правила сопоставления uri не могут существовать одновременно, т.е.

location /img/ {}
location ^~ /img/ {}

будет отображаться ошибка

nginx: [emerg] duplicate location "/img/" in /usr/local/etc/nginx/servers/test.conf:61

Обратите внимание, что uri со слэшем в конце и без слэша будут расцениваться как два совпадающих правила, и их обработка также отличается, что также упоминается в следующем примере (цитируется вышестатьяОписание в этом пункте кажется неверным).

Конкретный процесс сопоставления местоположения

  • Сначала проверьте неизмененные правила и выполните сопоставление префиксов, выберите самый длинный совпадающий элемент и запишите его.
  • Затем проверьте, есть ли точное совпадение местоположения (с модификатором =), если да, завершите поиск и используйте его конфигурацию.
  • Затем узнайте, есть ли оптимальное совпадение, если да, выберите элемент с самым длинным результатом оптимального совпадения и используйте его конфигурацию.
  • потомчтобыНайдите местоположение, определенное модификатором Regular, если оно совпадает, остановите поиск и используйте определенную им конфигурацию.
  • Наконец, если нет подходящего регулярного местоположения, используется самое длинное совпадающее местоположение символа префикса, записанное ранее.

Как видно из приведенного выше процесса сопоставления, порядок сопоставления следующий:

Точное совпадение > Лучшее соответствие > Обычное регулярное совпадение по порядку > Самое длинное совпадение префикса

Далее мы напишем несколько тестов для отработки локации, которая примерно выглядит так

# uri表示location的需要匹配的规则
location uri {
  	# config表示某个config配置
    [ config ]
}

Чтобы проверить вопрос «Какое правило сопоставления местоположения действует при наличии нескольких местоположений», мы можем перенаправить запрос в несуществующий файл, а затем использовать журнал ошибок для проверки местоположения, соответствующего запросу.

Теперь приступим к практическому тесту


server {
    listen 80;
    server_name test.com;
    index index.html;
  
    error_log  /usr/local/etc/nginx/logs/error.log error;
  
    location / {
        root /Users/Txm/A/;
    }
    location /img {
        root /Users/Txm/B/;
    }
    location /img/ {
        root /Users/Txm/C/;
    }
}

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

URL-адрес запроса правила сопоставления Примечание
test.com/s/img/1.png A Только/соответствует правилам сопоставления префиксов
test.com/IMG212/1 С вами… B Только /img соответствует префиксу, /img/ не соответствует
test.com/img/1/1.png C Есть разница между /img/ и /img с / в конце
test.com/img/1.png C Префикс /img/ соответствует большему количеству слов, чем /img

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

location ~* /im {
  root /Users/Txm/D/;
}
location ~* \.png {
  root /Users/Txm/E/;
}

посетите сейчас/img212/1.png,/img/1/1.pngа также/img/1.pngЭти три ссылки повлияют на правило D, такое как правило сопоставления выше:

  • Обычное сопоставление имеет приоритет над соответствием префикса, поэтому правило ABC не будет сопоставлено.
  • Обычное совпадение сопоставляется в соответствии с заданным порядком.Если оно совпадает, поиск останавливается, поэтому, хотя правило E также соответствует правилу, оно не срабатывает.

мы продолжаем тестировать^~лучший матч

location ~ /bund {
  root /Users/Txm/F/;
}
location ~ /bundle/1 {
  root /Users/Txm/F1/;
}
location ^~ /bundl {
  root /Users/Txm/G/;
}
location ^~ /bundle/ {
  root /Users/Txm/G1/;
}
location ~ \.js$ {
  root /Users/Txm/H/;
}

мы используемhttp://test.com/bundle/1.jsЭта ссылка используется для тестирования.Теоретически эта ссылка соответствует всем вышеперечисленным правилам.На самом деле запрос попадает в правила.G1, я так понимаю:

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

Следовательно, здесь происходит попадание в G1. Если G1 удаляется, G следует сопоставлять в соответствии с приоритетом, а G следует продолжать удалять. В это время состояние возвращается к указанному выше регулярному сопоставлению. Согласно правилам регулярного сопоставления в порядок, F должен соответствовать в это время.

Наконец, давайте проверим точное совпадение. Точное совпадение означает, что запрошенный путь должен точно совпадать с настроенным uri.

location = /img {
	root /Users/Txm/I/;
}
URL-адрес запроса правила сопоставления Примечание
test.com/img I Точное совпадение имеет наивысший приоритет
test.com/img/ D Точное паросочетание и оптимальное паросочетание не выполняются, но выполняется регулярное паросочетание D, чтобы

корень и псевдоним

Ссылаться на

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

Для указания пути к файлу можно использовать как root, так и псевдоним.Основное различие между ними заключается в том, как nginx интерпретирует uri за местоположением, что приводит к тому, что они по-разному сопоставляют запросы с файлами сервера.

  • Метод обработки root: корневой путь + путь к местоположению
  • Как работать с псевдонимом: замените путь местоположения на путь псевдонима

кhttp://test.com/test/index.htmlЗапрос, например,

server_name test.com;

location /test/ {
  # 当配置为root时,实际请求的Users/Txm/nginx_test/test/index.html
  # root可以放在 http、server、location、if等多个配置段下面
  # root /Users/Txm/nginx_test/; 
  
  # 当配置为alias时,实际请求的是/Users/Txm/nginx_test/index.html
  # alias只能放在location中
  # 注意alias末尾必须跟/
	alias /Users/Txm/nginx_test/; 
}

Другими словами, псевдоним — это определение псевдонима каталога, а корень — это определение каталога верхнего уровня.

В сочетании с местоположением, корнем или псевдонимом можно использовать для сопоставления запрошенного URL-адреса с соответствующим реальным каталогом на диске. Но в какой-то момент недостаточно просто иметь каталог без реального файла (самый распространенный сценарий, вероятно, заключается в том, что среда разработки не генерирует кэшированное значение хэша имени файла среды и.min.суффикс), вы можете пройтиrewriteПерепишите путь URI запроса.

rewrite

Ссылаться на

rewriteМодуль позволяет регулярно изменять URI запроса, инициировать внутренний переход, а затем сопоставлять местоположение или напрямую выполнять 30-кратное перенаправление для возврата к клиенту.

rewrite regex replacement [flag]

Регулярное выражение является обычным в стиле PCRE, а действующие правила перезаписи следующие:

  • Если регулярное выражение совпадает с uri текущего запроса, замена будет рассматриваться как новый uri для последующей обработки.
    • Если эти параметры установлены на уровне сервера, они вступят в силу до местоположения.
    • Если в новых символах URI есть что-то о протоколе, например http:// или https:// и т. д., прекратите обработку и ответьте напрямую с помощью 302.
  • Если существует несколько правил перезаписи, которые могут соответствовать uri в одном и том же контексте (сервер, местоположение, если), перезапись и замена будут выполняться непрерывно в соответствии с порядком, в котором появляются инструкции перезаписи, а замененная замена будет использоваться как новый uri для участия в последующих действиях.
  • Если вы хотите прервать матч, вы можете использовать флаг третьего параметра, значение которого выглядит следующим образом:
    • lastУказывает на прекращение обработки любых инструкций, связанных с перезаписью, и запуск следующего раунда сопоставления местоположения с замененным uri.
    • breakУказывает, что прекращает обработку любых инструкций, связанных с перезаписью, и напрямую использует uri для обработки запросов без сопоставления местоположения.
    • redirectЕсли он не содержит протокола и является новым uri, для обработки запроса будет использоваться местоположение, соответствующее новому uri, и 30-кратный переход не будет выполнен; однако он также может напрямую вернуть 30x и позволить браузеру перенаправить запрос сам по себе
    • permanentа такжеredirectТо же самое, разница в том, что он напрямую возвращает 301 постоянный редирект

должен быть в курсеlastа такжеbreakЕсли вы используете местоположение в местоположении, перенаправление будет повторно инициализировано с новым URI, и сопоставление местоположения будет выполнено снова. Если и новый uri, и старый uri снова совпадают с одним и тем же местоположением, возникнет бесконечный цикл. , когда этот цикл превышает 10 раз, nginx вернет 500. Так что имейте в виду:Использовать последний в контексте сервера и разорвать в контексте местоположения.

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

server {
    listen 80;
    server_name test2.com;
    index index.html;
    root  /Users/Txm/nginx_test/;

    access_log  /usr/local/etc/nginx/logs/test2.access.log;
    error_log  /usr/local/etc/nginx/logs/error2.log error;

	  rewrite ^/baidu http://www.baidu.com;
    rewrite ^/bai http://image.baidu.com;

    return 403;
}
URL-адрес запроса Окончательный переписать uri Примечание
test2.com/bai image.baidu.com
test2.com/baidu www.baidu.com Если он соответствует baidu, он вернется напрямую
затем добавьте местоположение
location /bundle/ {
	rewrite ^/bundle/(.*?)$ /dist/$1 break;
}

location /dist/ {
	rewrite ^/dist/(.*?)$ /src/$1 break;
}
URL-адрес запроса Окончательный переписать uri Примечание
test2.com/bundle/1.js /Users/Txm/nginx_test/dist/1.js break больше не выполняет сопоставление местоположения
test2.com/dist/1.js /Users/Txm/nginx_test/src/1.js

потом/bundle/идентификатор внутриbreakпревратиться вlast,

location /bundle/ {
  rewrite ^/bundle/(.*?)$ /dist/$1 break;
}

Затем вы можете увидеть окончательный uri и/dist/то же самое, переписанное как/Users/Txm/nginx_test/src/1.js, так что не забудьте использовать в местоположенииbreakпредупреждение.

С помощью перезаписи мы можем переписать путь и изменить некоторые несуществующие файлы на файлы, реально существующие на диске..minсуффикс и-hashПравила перезаписи суффиксов, которые можно использовать в элементах историиgruntУпакованные статические ресурсы сопоставляются с соответствующими исходными файлами src.

rewrite ^(.*?)((\.min)?\-.*?)(\..*?)$ $1$4 last;

Некоторое использование прокси nginx

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

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

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

Форвард-прокси прозрачен для нас и непрозрачен для сервера, то есть сервер не знает, получает ли он доступ с прокси или с реального клиента.

Ниже приведены некоторые функциональные сценарии, которые можно реализовать с помощью прокси-сервера nginx во фронтенд-разработке.

Моделирование сценариев онлайн-запросов в локальной среде разработки

Среду выполнения кода можно разделить на локальную среду разработки, тестовую среду и производственную онлайн-среду. В качестве примера возьмем веб-проект в существующем процессе разработки:

  • При разработке это номер порта 3015, запускаемый локально.
  • Во время теста тестовая платформа извлекает связанные сервисы в соответствии с порядком работы, развертывает их в контейнере через k8s и запускает сервис и, наконец, вводит серию списков хостов.
  • Когда рабочее задание может быть подключено к сети, объедините код для разработки и освоения с помощью платформы выпуска, а затем разверните его на рабочем сервере в соответствии с шагами команды.

Предположим, что ссылка для доступа к сервисуhttp://m.xxx.com/h5/testЧтобы добиться одинакового сценария доступа в трех средах, как правило, необходимо выполнить следующую обработку:

нужноДоступ к производственной среде, вы можете напрямую ввести текущую ссылку в браузере.Имя онлайн-домена обычно будет заранее разрешено к ip на соответствующем сервере.По умолчанию имя домена вводится для доступа к службам производственной среды.

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

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

127.0.0.1 xxx.com

Затем измените конфигурацию nginx через nginxxxx.comЗапрос доменного имени проксируется на номер порта локальной службы

server {
    listen 80;
    server_name m.xxx.com;

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_pass http://127.0.0.1:3015;
    }
}

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

Сопоставьте файлы ресурсов онлайн-запросов с локальными

Поскольку статические ресурсы в производственной среде, такие как таблицы стилей и файлы JavaScript, обычно сжимаются и упаковываются, к имени файла даже добавляется суффикс хеш для управления кешем.Если вам нужно отладить онлайн-код в какой-то момент, есть вообще два пути

Первый способ — передать запрошенный файл через инструмент захвата пакетов, такой как charlesMap LocalМетод сопоставляется с локальным диском.В это время запрошенный ресурс фактически возвращает локальный файл, и тогда цель отладки может быть достигнута путем изменения локального файла. Этот метод подходит для файлов, которые не подвергались слиянию и упаковке кода, и полезен для поддержки некоторых старых проектов, в которых для загрузки файлов используются инструменты управления модулями, такие как requirejs и seajs.

Второй — настроить доменное имя статического ресурса на локальное, а затем передать nginxlocation,aliasа такжеrewriteРеализовать прокси-сервер статических ресурсов

server  {
    listen 80;
    server_name cnd.shymean.com;
    
    location /wargame/ {
        alias /Users/Txm/github/wargame/dist/;
    		# 移除请求如jquery.min-a2dfg.js链接上的hash值a2dfg
    		# http://cnd.shymean.com/wargame/jquery.min-a2dfg.js 实际返回文件为 /Users/Txm/github/wargame/dist/jquery.min.js
        rewrite ^(.+)/(.+)[-.]\w+\.(\w+)$ $1/$2.$3 last;
    }
  
    location /blog/ {
    		# 直接映射到本地目录
        alias /Users/Txm/blog/public/;
    }
}

междоменная конфигурация nginx

Классический сценарий прямого прокси-сервера:Используйте nginx для обхода междоменных ограничений браузера, в процессе разработки и отладки с разделением интерфейса и сервера локальная функция интерфейса может бытьlocalhost:portВ виде доменных имен для разработки обычно используются локальные мок-данные.Если вам потребуется прямой доступ к удаленному интерфейсу для совместной отладки, вы столкнетесь с междоменными проблемами.

Этот сценарий в основном вызван несоответствием между доменным именем страницы (localhost) и доменным именем интерфейса (api.xxx.com) во время разработки.Через местоположение и proxy_pass nginx указанный запрос проксируется соответствующему поставщику услуг. С точки зрения браузера все запросы относятся к одному и тому же доменному имени, поэтому ограничений между доменами нет.

server {
    listen 80;
  	server_name shymean.com;
    location /api/ {
      	# 局域网中后台开发的本地服务,用于联调
        proxy_pass http://192.168.132.253:7654;
    }
}

Другой сценарий: в целях оптимизации производительности некоторые статические ресурсы часто используют отдельное доменное имя cdn, когда бизнесу необходимо использовать междоменные ресурсы (например, рисование сетевых изображений на холсте, вам нужно вызватьcanvas.toDataURL), в это время также будут междоменные ограничения через nginxadd_headerФункции могут очень просто реализовать CORS.

# 静态资源
map $http_origin $imgCorsHost {
    default 0;
    "~http://shymean.com" http://shymean.com;
    "~https://shymean.com" https://shymean.com;
}

server {
    listen 80;
    listen 443;
    server_name cdn.shymean.com;

    root /Users/Txm/Desktop/blog/static;
   
    add_header Access-Control-Allow-Origin $imgCorsHost;
    add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
    add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';

    if ($request_method = 'OPTIONS') {
        return 204;
    }
   
}

Как видно из приведенного выше примера, если вам нужно указатьAccess-Control-Allow-OriginДля нескольких доменных имен можно использовать структуру карты nginx.

Изменить содержимое ответа через nginx

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

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

<% if(!app.isProduction()) { %>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Mock.js/1.0.1-beta3/mock-min.js"></script>
    <%- IncludeAssets('start:statics/h5/act/js/_mock.js') %>
    <script>
        window.isMockReuquest = true
    </script>
<% } %>

В приведенном выше методе к коду добавляется дополнительный код оценки среды, а затем вводится фиктивный код.Путем перехвата и изменения содержимого ответа через nginx эта функция также может быть достигнута. Когда я впервые осознал это требование, я потратил много времени на поиск соответствующих методов реализации и обнаружил, что самый простой способ — черезopenrestyреализовать. Ссылаться на:

location ~* 1.js$ {
	body_filter_by_lua_file /usr/local/etc/openresty/lua/hello.lua;
}

затем добавьтеhello.luaСкрипт, напишите соответствующую логику

-- body_filter_by_lua, body filter模块,ngx.arg[1]代表输入的chunk,ngx.arg[2]代表当前chunk是否为last
local chunk, eof = ngx.arg[1], ngx.arg[2]
local buffered = ngx.ctx.buffered
if not buffered then
   buffered = {}  -- XXX we can use table.new here 
   ngx.ctx.buffered = buffered
end
if chunk ~= "" then
   buffered[#buffered + 1] = chunk
   ngx.arg[1] = nil
end
if eof then
   local whole = table.concat(buffered)
   ngx.ctx.buffered = nil
	 whole = string.gsub(whole, "console.log",  "console.warn")

   ngx.arg[1] = whole
end

Следует отметить, что модифицированныйwholeДлина содержимого не может превышать длину исходного содержимого, иначе будут перехвачены следующие данные.content-lengthсвязанные с головой. оopenrestyа такжеlua, у меня не было большого контакта с ним раньше, и я продолжу его углубленное изучение позже.

резюме

В этой статье обобщаются несколько директив, связанных с nginx, сопоставляющих uri, в том числе

  • использоватьlocationсоответствовать ури
  • использоватьrootа такжеaliasУкажите каталог ресурсов запроса
  • использоватьrewriteПереписать uri и последующие правила сопоставления

Комбинируя uri и proxy, мы можем направить запрос к ресурсам, которые нам нужны для удовлетворения различных потребностей разработки в среде разработки.