1. Внешний (301) редирект выполняет не Apache, а m
- Внешний (301) редирект выполняет не Apache, а modx (судя по всему, анализирует содержимое полей глобальной переменной $_SERVER — иначе как modx узнает, что на уровне веб-сервера был изменён URI ресурса, который ему втюхали)
Всё так и есть. При включенных дружественных URL и включенной опции (friendly_urls_strict) в методе (modRequest::_cleanResourceIdentifier()) выполняется внешний (301) редирект с внешнего URI (запрошенного со стороны браузера) на внутренний URI того ресурса, который должен отображаться:
/**
* Cleans the resource identifier from the request params.
*
* @param string $identifier The raw identifier.
* @return string|integer The cleansed identifier.
*/
public function _cleanResourceIdentifier($identifier) {
if (empty ($identifier)) {
...
}
elseif ($this->modx->getOption('friendly_urls', null, false) && $this->modx->resourceMethod == 'alias') {
$containerSuffix = trim($this->modx->getOption('container_suffix', null, ''));
$found = $this->modx->findResource($identifier);
if ($found === false && !empty ($containerSuffix)) {
...
} elseif ((integer) $this->modx->getOption('site_start', null, 1) === $found) {
...
} else {
if ($this->modx->getOption('friendly_urls_strict', null, false)) {
$requestUri = $_SERVER['REQUEST_URI'];
$qsPos = strpos($requestUri, '?');
if ($qsPos !== false) $requestUri = substr($requestUri, 0, $qsPos);
$fullId = $this->modx->getOption('base_url', null, MODX_BASE_URL) . $identifier;
$requestUri = urldecode($requestUri);
if ($fullId !== $requestUri && strpos($requestUri, $fullId) !== 0) {
$parameters = $this->getParameters();
unset($parameters[$this->modx->getOption('request_param_alias')]);
$url = $this->modx->makeUrl($found, $this->modx->context->get('key'), $parameters, 'full');
$this->modx->sendRedirect($url, array('responseCode' => 'HTTP/1.1 301 Moved Permanently'));
}
}
...
}
} else {
...
}
return $identifier;
}
Это штатные действия modx, которые реализуют логику «строгих» (канонических) URL при включении опции (friendly_urls_strict):
Если выбрано «Да», неканонические запросы, соответствующие ресурсу, будут перенаправлены с кодом 301 на канонический URI для этого ресурса. WARNING: Do not enable if you use custom rewrite rules which do not match at least the beginning of the canonical URI. For example, a canonical URI of foo/ with custom rewrites for foo/bar.html would work, but attempts to rewrite bar/foo.html as foo/ would force a redirect to foo/ with this option enabled.
— Поэтому, если одновременно необходимо:
а) исключить URI-дубли страниц включением опции (friendly_urls_strict) (необходимо для SEO)
б) на уровне веб-сервера выполнять внутренний редирект с одного ресурса на другой
то нужно будет выполнить следующие действия:
- Включить опцию
(friendly_urls_strict) - Прописать требуемые директивы для редиректа в настройках веб-сервера (или в
.htaccess) - В плагине на событии
(OnHandleRequest)(последнее событие, которое генерируется до вызова методаmodRequest::_cleanResourceIdentifier()) установить эту опцию в значение(false)для тех исходных URL, для которых выполняется внутренний редирект на уровне веб-сервера (выявить такие ситуации можно сравнением значения глобальной переменной$_SERVER['REQUEST_URI']и значением переменной запросаq($modx->getOption('request_param_alias')) — именно так и делает методmodRequest::_cleanResourceIdentifier()) - (НЕ ОБЯЗАТЕЛЬНО) В плагине на событии
(OnWebPageInit)(первое событие, которое генерируется после вызова методаmodRequest::_cleanResourceIdentifier()) установить эту опцию в исходное значение (исходное значение при этом нужно запомнить в предыдущем плагине).
P.S. При таком подходе в тех случаях, когда выполняется внутренний редирект на уровне веб-сервера, контролировать уникальность внешних URL придётся самому (поскольку для этих случаев описанными выше действиями мы отключаем такой контроль со стороны modx).