IIS: URL Rewrite, кэширование, статические файлы и пхп
Обычно в проектах использую стоковый web.config для проекта, и особо не приходилось иметь дела с настройками переопределения URL и кеширования на стороне IIS. Теперь вот не могу разобраться.
Итак ситуация следующая. Имеется проект на пхп. Поскольку контент главной страницы обновляется редко имеет смысл ее закэшировать чтобы вообще пхп не дергать лишний раз. Как это выглядит с точки зрения маршрутизации в проекте:
$routes->connect('/', ['controller' => "Home"]);
$routes->connect('/cache/index.html', ['controller' => "Home", 'action' => 'index']);
есть два пути, которые приводят на главную. Допустим, первый раз мы зашли, сработал первый путь, попадаем в Home/index и там делаем следующее:
....
$debug = Configure::read('debug');
if(!$debug) {
$html = $this->render('index');
$cfilename = APP_DATA . DS . "cache" . DS . "index.html";
file_put_contents($cfilename, $html);
}
В общем говоря генерим шаблоны и результат записываем в cache/index.html.
Далее в терминах htaccess добавляем правило
RewriteRule ^$ cache/index.html
и аналогично для IIS:
<rule name="cachedIndex" stopProcessing="false">
<match url="^$" ignoreCase="false" />
<action type="Rewrite" url="cache/index.html" appendQueryString="true" />
</rule>
в общем говоря заход на главную теперь перенаправляется на cache/index.html. Если файл сгенерирован, то он просто отдается сервером. Если его нет, то управление передается на уровень пхп и он этот файл генерирует.
Когда в приложении данные меняются, файл будет удален, и соответственно при очередном заходе на сайт будет создан новый - актуальный.
Далее хочу этот файл закэшировать на уровне ядра сервера. Добавляю кэширование для html-типа, и ставлю галку на - получение события изменения файла.
И тут короче все вообще плохо становится. По какой то причине кэш не обновляется если я файл редактирую. Я ожидаю, что сервер должен получить какое-то уведомление, что файл изменен, и обновить кэш. Но этого не происходит. (черт с ним, допустим сделаю обновление раз в минуту). Но теперь, если мой файл удаляется, то сервер просто отдает 404. Причем серверную, а не пхп-шную.
Ошибка HTTP 404.0 - Not Found
Разыскиваемый вами ресурс был удален, было изменено его имя или он временно недоступен.
Подробные сведения об ошибке:
Модуль IIS Web Core
Уведомление MapRequestHandler
Обработчик StaticFile
Код ошибки 0x80070002
Запрошенный URL-адрес http://example.com:80/webroot/cache/index.html
Физический путь C:\inetpub\example.com\webroot\cache\index.html
Не понимаю, как тут теперь передать управление на уровень пхп?
Полный вид конфига на текущий момент такой:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="cachedIndex" stopProcessing="false">
<match url="^$" ignoreCase="false" />
<action type="Rewrite" url="cache/index.html" appendQueryString="true" />
</rule>
<rule name="Exclude direct access to webroot/*" stopProcessing="true">
<match url="^webroot/(.*)$" ignoreCase="false" />
<action type="None" />
</rule>
<rule name="Rewrite routed access to assets(img, css, files, js, favicon)" stopProcessing="true">
<match url="^(cache|img|css|files|js|webfonts|favicon|robots.txt)(.*)$" />
<action type="Rewrite" url="webroot/{R:1}{R:2}" appendQueryString="false" />
</rule>
<rule name="Rewrite requested file/folder to index.php" stopProcessing="true">
<match url="^(.*)$" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
</conditions>
<action type="Rewrite" url="index.php" appendQueryString="true" />
</rule>
</rules>
</rewrite>
<handlers>
<clear />
<add name="php-7.1.15" path="*.php" verb="GET,HEAD,POST" modules="FastCgiModule" scriptProcessor="C:\Program Files (x86)\PHP\v7.1.15\php-cgi.exe" resourceType="Either" requireAccess="Script" />
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />
</handlers>
<defaultDocument>
<files>
<clear />
<add value="Default.htm" />
<add value="Default.asp" />
<add value="index.htm" />
<add value="index.html" />
<add value="iisstart.htm" />
<add value="index.php" />
<add value="default.aspx" />
</files>
</defaultDocument>
<caching>
<profiles>
<add extension=".html" policy="DontCache" kernelCachePolicy="DontCache" duration="00:00:30" />
</profiles>
</caching>
<urlCompression doStaticCompression="false" />
</system.webServer>
</configuration>
В общем, как мне реализовать этот базовый сценарий кэширования:
1) заход на главную - внутренний редирект на /cache/index.html
2) если этот файл есть - отдать
3) если файла нет - передать управление в пхп, пусть генерит.
и теперь чтобы вообще исключить обращение к файловой системе, закэшировать файл сервером до тех пор пока он не будет удален в результате обновления данных на сайте.
Ответы (1 шт):
Еще пара часов копания, и решение кажется все же нашлось. Шаги которые помогли разрулить ситуацию, и в том числе подводные камни которые еще обнаружились.
Почему выдавалась 404я ошибка при отсутствии файла. Очевидно, дело было в третьем правиле для статической отдачи css/js и т.п. Поскольку там стоит
stopProcessing, то файл не найден, и на этом все. Сервер отдает 404, обработка заканчивается.Убрал проверку
cacheиз этого правила. Теперь управление передается далее. Но здесьconditionпроверяет путьcache/index.html, хотя фактический путь будетwebroot/cache/index. Так что пхп код срабатывает каждый раз при обращении.
Тут достаточно было бы перенаправить наш/наwebroot/cache/index.html, но тогда его второе правило сразу отрежет. Так что простое решение - убрать папкуcacheизwebrootна уровень выше.Реальный файл хранился в
/app_data/cache, аwebroot/cacheбыла симлинком. В общем перенаправить наapp_data/cache/прямо нельзя, посколькуapp_dataштука зарезервирована в IIS и доступа туда нет. Так что в корне сделан симлинкcache -> app_data/cache.Казалось бы теперь все должно быть хорошо. но файл кэшируется. Казалось бы это хорошо, но файл кэшируется даже при условиях что все кэширования отключены. И он отдается в том виде, пока мы не перезапустим пул.
Нагуглился вот такой вопрос на английском СО - https://stackoverflow.com/q/6698481/1216425 У человека также при отключенном кэше файл продолжал кэшироваться и отдаваться неизменным если был симлинком. После того, как была убрана ссылка
cache -> app_data/cacheи сделана просто директорияcacheвсе вроде стало работать.
Теперь настройки кэширования про изменения вроде как адекватно подхватывают обновления файла.