Эта статья синхронизирована в личном блогеshymean.comвверх, добро пожаловать, чтобы следовать
В этой статье разбирается метод использования nginx для перезаписи uri и прокси-функций при фронтенд-разработке в среде разработки.
Ссылаться на
- китайская документация nginx
- Необходимые знания Nginx для фронтенд-разработчиков
- Nginx и фронтенд разработка
совпадение местоположения
Ссылаться на
Когда несколько проектов используют одно и то же доменное имя, часто необходимо перенаправлять запросы в разные проекты в соответствии с 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, мы можем направить запрос к ресурсам, которые нам нужны для удовлетворения различных потребностей разработки в среде разработки.