mod_rewrite пытается перенаправить, если папка существует - PullRequest
0 голосов
/ 05 марта 2020

У меня есть HTTP-API, написанный на PHP, и я перенаправляю все вызовы на свой индекс. php, где (Slim-) маршрутизатор делает все остальное. Это работает.

Мое перенаправление в .htaccess выглядит следующим образом:

Options +FollowSymLinks
Options -Indexes

RewriteEngine on
RewriteRule ^ index.php [QSA,L]

Существует только одна проблема: если одна конечная точка названа идентично с существующей папкой, происходят странные вещи. Это тот случай, когда я создаю конечную точку [PUT] /test, в то время как есть также папка с именем test, содержащая модульные тесты.

Вот что происходит:

  • Если я вызов [PUT] /test с предпечатной проверкой Я вообще не получаю ответа на вызов OPTIONS, который приводит к сбою приложения. Это настоящий проблемный случай, так как мне нужен CORS.
  • Если я вызываю его без предварительной проверки и PUT, я получаю переадресацию 301 на одну и ту же конечную точку.
  • Если я вызываю ее без предварительной проверки и POST, получаю 301 пересылка на ту же конечную точку, но с GET?!

Я думаю, мне нужно что-то изменить в .htaccess, чтобы игнорировать существование папки, но что?

Как воспроизвести

Иметь сервер Apache и создать каталог следующим образом:

  • / цель
  • / цель / .htaccess
Options +FollowSymLinks
Options -Indexes

RewriteEngine on
RewriteRule ^ index.php [QSA,L]
  • / цель / индекс. php
<?php echo $_SERVER['REQUEST_URI'];
  • / target / subfolder

  • / testscript. html

<!DOCTYPE HTML>
<html lang="en">
<head>
    <title>test</title>
    <style>
        div {margin: 0.5em;}
        .error { background: rgba(255, 0, 0, 0.3);}
        .success { background: rgba(0, 255, 0, 0.3);}
    </style>
</head>
<body>


<script>
    const call = (url) => {

        fetch(url, {
            redirect: "manual",
            method: "POST"
        }).then(async response => {
            const className = (response.redirected) ? 'success' : 'error';
            const content = await response.text();
            document.querySelector('body').innerHTML += `<div class='${className}'>${url}<hr /><b>[${response.status}]</b> ${content}</div>`;
        });
    };

    call('target/endpoint');
    call('target/subfolder');

</script>

</body>
</html>

Открыть http://localhost/ ... testscript.html в браузере и видите: вызов на target/subfolder изменил свой метод. Также, когда вы смотрите на вкладку сети в консоли браузера, вы видите, что было 301 переадресация. Почему? И еще важнее: как я могу обойти это. Мое желаемое поведение - это перезапись без каких-либо изменений с точки зрения метода на index.php, несмотря на существование папки с таким именем. Другими словами: то же самое, что происходит, когда я звоню target/endpoint для target/subfolder.

Я знаю о -d-f) естественно, но это можно использовать - насколько я знаю - чтобы управлять поведением в зависимости от того, существует ли файл или папка - поэтому я предположил бы, что без этих флагов существование каталога не должно играть никакой роли, но это, по-видимому, действительно.

Ответы [ 2 ]

1 голос
/ 05 марта 2020

Итак, сначала причина 301:

  1. Вы запрашиваете URI /target/subfolder, который фактически указывает на каталог на вашем сайте.
  2. Поскольку ваш URI является пропуская висячий сл sh. mod_dir модуль Apache вступает в действие и отправляет перенаправление 301, делая его /target/subfolder/. Это сделано из соображений безопасности, чтобы избежать раскрытия содержимого вашего каталога в Интернете.

Чтобы исправить это, вы можете просто использовать call с конечным символом sh везде, где он указывает на каталог:

call('target/subfolder/');

Но это громоздко, поскольку разработчики внешнего интерфейса не всегда будут знать эти конкретные c случаи.

Вы можете использовать общее правило c в своем .htaccess или Apache config, чтобы добавить этот конечный sla sh:

# add a trailing slash to directories
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule [^/]$ %{REQUEST_URI}/ [L,R=301,NE]

Убедитесь, что это правило находится чуть ниже линии RewriteEngine On и перед вашими существующими правилами.

0 голосов
/ 06 марта 2020

С помощью @anuhava я нашел правильный способ решить эту проблему. Один только его ответ не помог, но привел меня к этой теме , и я обнаружил, что война решений фактически отключила автоматов c trailing sla sh в .htaccess:

DirectorySlash Off

У меня было дополнительное (не упомянутое ранее) требование для определения каталога исключений, который должен быть доступен напрямую. Чтобы сделать это возможным, мне нужно было правило @anuhava, и я согласен с этим .htaccess:

DirectorySlash Off

Options +FollowSymLinks
Options -Indexes

RewriteEngine on

# add a trailing slash to directories
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule [^/]$ %{REQUEST_URI}/ [L]

# rewrite all calls excpet for exception_dir to index.php
RewriteCond %{REQUEST_URI} !/target/exception_dir
RewriteRule ^ index.php [QSA,L]
...