перенаправить 404 на похожие URL - PullRequest
31 голосов
/ 20 января 2012

У меня есть сайт с историями. Я могу иметь несколько типов историй в нескольких категориях, таких как:

  • дети
  • романтика
  • SciFi
  • действие
  • thriler
  • квеста

Истории доступны по таким URL-адресам, как:

www.example.com/action/story-name-action/
www.example.com/romance/story-name-romance/

и первый параметр (действие) и второй (история-имя-действие) перенаправляются с помощью .htaccess с использованием правил. Эта часть отлично работает.

В последнее время я получаю несколько десятков 404 с разных сайтов, и вот что я хочу сделать, но я не знаю, как:

Если кто-то печатает, например: /action/story-nme-ction, я хочу перенаправить на: action/story-name-action/

Есть ли эффективный способ реализовать это?

Ответы [ 6 ]

37 голосов
/ 20 января 2012

О, человек, о человек!

То, что вы просите, непросто, и вам нужен мощный компьютер, но результаты просто потрясающие.

Вот что я бы предложил сделать:

  • Для правильной обработки 404 у вас есть перенаправление ErrorDocument в конфигурации vhost. Моя выглядит так: ErrorDocument 404 /404.php;
  • При наличии 404 Apache будет вызывать /404.php со всеми аргументами (какой неверный URL и т. Д., Чтобы увидеть это, выведите дамп $_SERVER). Вы должны проверить, есть ли в URL только два выражения / т.е. http://mysite.com/(expr1)/(expr2)/
  • Если нет, тогда сделайте классический 404.
  • Если да, тогда выполните поиск SOUNDEX с MySQL (в вашем файле 404 Php). Смотрите пример запроса здесь .
  • Затем, в этом «особом» случае 404, сделайте предложение, как в Google, т.е.: «Вы имели в виду /action/story-name-action/? Если так, нажмите на ссылку».

Это тяжелая работа, но она интересна и показывает ваше мастерство. Очень немногие веб-сайты делают это (я просто знаю, Google на самом деле).

Вот моя демонстрация на моем французском столе, которая может дать вам общее представление о том, как это работает:

mysql> SELECT * FROM job WHERE
SOUNDEX( description ) LIKE SOUNDEX('Machiniste cinéma');
+-------+--------------------+
| id    | description        |
+-------+--------------------+
| 14018 | Machiniste cinéma  |
+-------+--------------------+
1 row in set (0.06 sec)

mysql> SELECT * FROM job WHERE
SOUNDEX( description ) LIKE SOUNDEX('Mchiniste cinéma');
+-------+--------------------+
| id    | description        |
+-------+--------------------+
| 14018 | Machiniste cinéma  |
+-------+--------------------+
1 row in set (0.06 sec)

mysql> SELECT * FROM job WHERE
SOUNDEX( description ) LIKE SOUNDEX('Machnste cinema');
+-------+--------------------+
| id    | description        |
+-------+--------------------+
| 14018 | Machiniste cinéma  |
+-------+--------------------+
1 row in set (0.06 sec)

mysql> 
18 голосов
/ 20 января 2012

Если вы не очень уверены в URL-адресе, на который пользователь действительно хотел перейти, использование перезаписи / перенаправления на конкретный URL является очень плохой идеей.

Если взять ваш пример, предположим, что вы хотите обработать каждый случай, когда две буквы могли быть пропущены, с 17 символами в последней части URL, то есть 17 * 16 = 272 комбинации, в то время как может быть возможно сопоставить несколько ' ложные URL с одним регулярным выражением, вам все еще понадобится много правил переписывания.

Лучшим решением было бы реализовать обработчик 404 с использованием PHP (поскольку вы включили этот тег в свой q), чтобы сгенерировать список (скажем) 10 лучших URL-адресов, пути которых имеют самое короткое расстояние Левенштейна от запрошенного пути вместе со ссылкой по умолчанию и вспомогательным текстом. (Существуют реализации на основе MySQL - попробуйте Google для URL). Обработчик NB по-прежнему должен возвращать статус 404 - HTML-содержимое NB должно быть больше минимальной длины, чтобы подавить «дружественное» сообщение об ошибке MSIE.

7 голосов
/ 03 февраля 2012

Если вы знаете, какими могут быть правильные URL-адреса, вы можете использовать:

levenshtein($givenURL, $possibleURL)

Пример из PHP документации, комментарии для краткости удалены:

$input = 'carrrot';

$words  = array('apple','pineapple','banana','orange',
                'radish','carrot','pea','bean','potato');

$shortest = -1;

foreach ($words as $word) {
    $lev = levenshtein($input, $word);
    if ($lev == 0) {
        $closest = $word;
        $shortest = 0;
        break;
    }
    if ($lev <= $shortest || $shortest < 0) {
        $closest  = $word;
        $shortest = $lev;
    }
}

echo $shortest == 0 ? "Exact match found: $closest\n" : "Did you mean: $closest?\n";

Выходы:

Вводимое слово: морковь
Вы имели в виду морковь?

Это хорошо, когда вы думаете, что люди, возможно, пропустили букву или вставили дополнительную, но это может потерпеть неудачу, когда люди искренне не знают, как написать слово и придумали что-то творческое!

Если вы предпочитаете маршрут soundex(), взгляните на функцию metaphone().

Мне нравится идея использования metaphone() вместе с levenshtein() или similar_text(), поскольку оно возвращает фонетическое представление слова, и вы все еще хотите увидеть, насколько оно похоже на ваш оригинал .

Примеры:

metaphone('name') = NM
metaphone('naaaaaameeeeeeee') = NM
metaphone('naiym') = NM
metaphone('naiyem') = NYM

Несмотря на то, что многие орфографические ошибки возвращают одинаковое совпадение, последний пример показывает, что вы действительно хотите найти самое близкое совпадение с чем-то вроде levenshtein()

Для эффективности, если вы используете другой файл 404, в котором перезаписи пытались соответствовать этому шаблону и потерпели неудачу, чем вы используете для остальной части сайта, это действительно не должно быть огромными накладными расходами.

Если вы получаете одни и те же 404 от одного и того же реферера (и не можете заставить их изменить ссылку), возможно, в этом случае стоит включить статическую перезапись.

4 голосов
/ 20 января 2012

Есть несколько решений:

  • Определите источник неисправных URL. Этого просто не должно происходить, и я не могу представить, почему это происходит. Связывают ли другие люди откуда-то еще, и они сделали опечатку (игнорируя существование копирования и вставки)? Вы можете видеть, откуда это (реферер), и связаться с ними?
  • Добавьте идентификатор к URL, так что /action/123/story-name-action, где вы просматриваете статью по идентификатору, а не по ее заголовку (бонус: добавляет возможность создания нескольких историй одной и той же категории с одинаковым заголовком)
  • Выполните нечеткий поиск по названию, используя что-то вроде soundex , и перенаправьте пользователя к наиболее подходящему заголовку или покажите страницу обзора с похожими заголовками, такими как @symcbean предлагает.

Хотя я предпочитаю идентификационный номер.

1 голос
/ 20 января 2012

Мы установили перенаправления на страницу поиска для URL, как это - наш поиск "предложил" функцию.

0 голосов
/ 20 января 2012

Поскольку значения (предположительно) извлекаются из MySQL на основе заголовка, вы можете поместить индекс FULLTEXT в столбец заголовка и использовать функцию MySQL MATCH(), чтобы найти наиболеесоответствующее соответствие, и перенаправьте пользователя на это.

Хотя это ни в коем случае не будет идеальным решением - тип интеллекта, требуемый для этого с любой реальной степенью точности, слишком опасно приближается к * 1007тест территория.

...