Вопрос или проблема
У меня есть локальный сервер Tomcat, который я разрабатываю, используя локальный экземпляр IIS в качестве прокси.
Я делаю это потому, что развертывание сервера — это мучительный процесс, так как много контента не является (как я бы это описал) самодостаточным. Контент из различных проектов в основном копируется в корневую директорию сервера. Я не хотел бы сталкиваться с этой проблемой настройки, поэтому с помощью модуля перезаписи я мог бы в основном переписывать URL на виртуальные директории.
Например,
/js/* -> /someproject/js/*
/css/* -> /someproject/css/*
/**/*.pdf -> /someotherproject/pdf/*
Однако есть несколько крайних случаев, когда эта схема не работает, особенно когда есть пересечение в целевых директориях. В развертывании некоторые ресурсы помещаются в одну и ту же директорию, поэтому нет реального способа различить, что есть что. У этих файлов нет строгого шаблона, это смешанная куча.
Например,
/someproject1/file1.txt -> /file1.txt
/someproject2/book2.doc -> /book2.doc
Таким образом, учитывая URL /file1.txt
, я не знал бы, могу ли я переписать его, чтобы перейти к someproject1
или someproject2
. Я подумываю, что это может сработать, если будет какой-то порядок тому, к каким URL пытаться переписать. Таким образом, я мог бы взять URL, например, /file3.txt
, и переписать его на первый из этих шаблонов, который оказывается действительным.
/someproject1/file3.txt # если 404, попробуйте следующее
/someproject2/file3.txt # если 404, попробуйте следующее
/someotherproject/file3.txt # если 404, попробуйте следующее
/file3.txt # запасной вариант
Можно ли выразить это только с помощью модуля перезаписи URL?
Мне удалось заставить это работать.
Первой трудностью было то, что я не осознавал, что не все типы условных совпадений доступны в глобальной области (где я и писал свои правила). Доступен был только Pattern
. Мне пришлось изменить область на “распределенную” (правила по сайту), чтобы получить доступ к типам совпадения IsFile
и IsDirectory
.
С этого момента я мог написать свои правила с каким-то видом иерархии. Сначала переписывайте, чтобы соответствовать шаблону, который я хочу попробовать первым, затем, если он не разрешается в файл, переписывайте его на следующий шаблон и повторяйте.
<rule name="try in project/content" stopProcessing="false">
<match url=".*" />
<action type="Rewrite" url="project/content/{R:0}" />
</rule>
<rule name="verify project/content" stopProcessing="false">
<match url="(project)/content(/.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="{R:1}{R:2}" />
</rule>
В моем конкретном случае я хотел сначала попытаться в определенной подпапке, а затем попробовать родительские директории, если их не существует. Но теоретически я мог бы сделать это для любого набора путей, если я знаю, в каком порядке их пробовать.
Таким образом, для моего примера в вопросе я установлю эти правила:
<rule name="try in someproject1" stopProcessing="false">
<match url=".*" />
<action type="Rewrite" url="someproject1/{R:0}" />
</rule>
<rule name="try in someproject2 otherwise" stopProcessing="false">
<match url="someproject1/(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="someproject2/{R:1}" />
</rule>
<rule name="try in someotherproject otherwise" stopProcessing="false">
<match url="someproject2/(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="someotherproject/{R:1}" />
</rule>
<rule name="fallback to root otherwise" stopProcessing="false">
<match url="someotherproject/(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="{R:1}" />
</rule>
Ответ или решение
Конечно, я помогу вам с реализацией процесса перенаправления URL в условиях недоступности ресурсов, что приводит к ошибке 404. Ниже представлено подробное решение вашей задачи, использующее модуль переписывания URL в IIS.
Введение в проблему
В ходе разработки на локальном сервере Tomcat с использованием IIS в качестве прокси, вы столкнулись с проблемой многоуровневого перенаправления URL. Существуют случаи, когда определенные файлы находятся в разных проектах, и их невозможно однозначно идентифицировать по названию. Ваша цель – разработать систему, которая сначала попытается найти файл в одном проекте, и только затем продолжит поиск в других.
Стратегия решения
Для реализации данного механизма вы можете воспользоваться правилами переработки URL в IIS, написав последовательность правил, которые будут проверять существование файла и, в случае отсутствия, пытаться перенаправить на следующий путь.
Пример конфигурации правил
Чтобы добиться требуемого результата, вы можете использовать следующие правила переписывания:
<rule name="Пробуем найти в someproject1" stopProcessing="false">
<match url=".*" />
<action type="Rewrite" url="someproject1/{R:0}" />
</rule>
<rule name="Пробуем найти в someproject2, если не найдено" stopProcessing="false">
<match url="someproject1/(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="someproject2/{R:1}" />
</rule>
<rule name="Пробуем найти в someotherproject, если не найдено" stopProcessing="false">
<match url="someproject2/(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="someotherproject/{R:1}" />
</rule>
<rule name="Резервный вариант: корень проекта" stopProcessing="false">
<match url="someotherproject/(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="{R:1}" />
</rule>
Пояснение правил
- Первое правило: Принимает любой запрос и пытается переписывать его в директорию
someproject1
. - Второе правило: Если файл не найден в
someproject1
, происходит попытка поиска вsomeproject2
. - Третье правило: Аналогично, если файл отсутствует в
someproject2
, проводится проверка вsomeotherproject
. - Четвёртое правило: В качестве последнего шага выполняется попытка обратиться к корневой директории.
Заключение
Данная структура позволяет гибко управлять перенаправлением запросов и свести к минимуму возникновение ошибок 404. Убедитесь, что ваше приложение корректно обрабатывает конфликты в именах файлов, и используйте модуль переписывания IIS, чтобы управлять очередностью проверки доступных ресурсов. Понимание базовых концепций работы с URL и правил переписывания является ключом к успешной реализации данной стратегии.
Эта реализованная схема не только поможет вам избежать потерь в ненужных 404 ошибках, но и повысит общий пользовательский опыт ваших конечных пользователей.