Назад | Перейти на главную страницу

Неожиданное поведение относительного ErrorDocument .htaccess

В корне документа я помещаю .htaccess с:

ErrorDocument 404 /error.php

Поскольку он находится в файле .htaccess, Apache ищет error.php в относительном пути, поэтому я могу поместить разные файлы error.php в разные подпапки, чтобы заставить его выполнять другой error.php:

request /app1/not-exists.txt : yields /app1/error.php
request /app2/not-exists.txt : yields /app2/error.php
request /not-exists/not-exists.txt : yields /error.php

Это желаемое поведение. Тем не мение,

request /not-exists/app1/not-exists.txt : yields /app1/error.php
request /app2/app1/not-exists.txt : yields /app1/error.php

Это не похоже на ожидаемое поведение. Я ожидал:

request /not-exists/app1/not-exists.txt : yields /error.php
request /app2/app1/not-exists.txt : yields /app2/error.php (or maybe /error.php)

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

Я думаю, что ваше недоразумение здесь относительное.

.htaccess файлы не имеют особого поведения, которое заставляет пути быть относительными; они по сути то же самое, что <Directory> блок с точки зрения поведения конфигурации.

ErrorDocument не имеет понятия о контексте; когда вы вступаете на путь вроде /error.php всегда предполагается, что он относится к корню документа, независимо от того, где он настроен. mod_rewrite конфигурация в <Directory> блокировать или .htaccess file использует относительные пути, что, вероятно, вы и думаете для такого поведения.

Пара вариантов того, как вы могли бы это реализовать ... у вас может быть один error.php который извлекает содержимое из файлов ошибок для каждого приложения в зависимости от пути запроса?

Или вы могли бы просто использовать mod_rewrite чтобы получить желаемое поведение выбора страницы ошибки (хотя получение логики, соответствующей тому, что вы ищете, представляет собой немного сложный беспорядок):

<Directory /path/to/docroot>
    # First, we'll have a rule that will handle looking for an error.php in
    # the app directory that the request is in...
    # Not a file or a directory that exists:
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    # Capture the application directory that we're trying to load from (if
    # there is one) for use in the next rule:
    RewriteCond %{REQUEST_FILENAME} ^/path/to/docroot/([^/]+)/
    # Check if an error.php exists in that directory;
    RewriteCond /path/to/docroot/%1/error.php -f
    # Send the response to the error page.  It should set the 404 response code.
    RewriteRule ^([^/]+)/.*$ $1/error.php [L]

    # Ok, the previous pile of rules didn't apply;  if the user's requesting 
    # a nonexistent resource, then either the user's not in an app subdirectory,
    # or they're in a subdirectory that didn't have an error.php.
    # So, this is a lot simpler:
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^ error.php [L]
</Directory>