将404重定向到相似的URL。

31

我有一个包含故事的网站。这些故事可以分成多个不同类型和类别,例如:

  • 儿童
  • 浪漫
  • 科幻
  • 动作
  • 惊悚
  • 任务

通过以下网址可以访问这些故事:

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

第一个参数(action)和第二个参数(story-name-action)是使用.htaccess规则重定向的。这部分工作得很好。

最近,我从不同的网站收到了几十个404错误,以下是我想做的事情,但我不知道该怎么做:

如果有人输入:例如:/action/story-nme-ction,我想要重定向到:action/story-name-action/

有没有一种有效的方法来实现这个目标?


2
对于静态文件,可以使用mod_speling - Simon Richter
1
我从不同的网站上收到了几十个404错误。这是什么意思?你的意思是这些网站有指向你的网站的错误链接吗? - Lightness Races in Orbit
6个回答

37

哎呀,这不简单,需要一台强大的计算机,但结果非常惊人。

我建议你这样做:

  • 对于404的正确处理,您可以在虚拟主机配置中使用ErrorDocument重定向。我的配置看起来像这样:ErrorDocument 404 /404.php;
  • 当出现404错误时,Apache将调用/404.php并将所有参数传递给它(包括坏的URL等等,在$_SERVER中转储以查看)。您必须测试URL中是否只有两个表达式/,即http://mysite.com/(expr1)/(expr2)/
  • 如果不是,则执行经典的404。
  • 如果是,则在您的404 Php文件中使用MySQL进行SOUNDEX搜索。查询示例在此处查看。
  • 然后,在这种“特殊”的404情况下,提供建议,就像谷歌一样,即:“您是否意思是/action/story-name-action/? 如果是,请单击链接”。

这是一项艰苦的工作,但它非常有趣且展示了您的技能。很少有网站这样做(我只知道谷歌实际上这样做)。

这里是一个演示我的法语表,可以让您了解它的工作原理:

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> 

2
你说得对。我刚刚提出的是最接近 Natalia 想要的唯一解决方案。而她想要的几乎是不可能实现的。 - Olivier Pons
1
谢谢您提供Typex的信息,我之前从未听说过,并且在谷歌上也没有找到有价值的链接。我同意这需要花费很多时间来解决百分之几的错误。不管怎样...您是否尝试在MySQL中执行像SELECT * FROM table WHERE SOUNDEX( table.column ) LIKE SOUNDEX('story-nme-ction')这样的查询?我已经在我的问题中编辑了一个实际演示 =) - Olivier Pons
1
如果你有“Typex”的一些链接,我很感兴趣! - Olivier Pons
1
因为您查询了 WHERE SOUNDEX(description) LIKE SOUNDEX('Machnste cinema'),所以您应该将 SOUNDEX(description) 存储在它自己的列中,比如 descriptionex。然后您可以使用 WHERE descriptionex LIKE SOUNDEX('Machnste cinema') 进行查询。descriptionex 是可索引的,对性能有很大帮助。 - Stephen Quan
你说得完全正确。我并不是在谈论性能,只是想引导娜塔莉娅走向正确的方向。感谢您提供的这个优化建议! - Olivier Pons
显示剩余2条评论

18

除非你非常确定用户想要导航到的URL,否则使用重写/重定向到特定URL是一个非常糟糕的主意。

以你的例子为例,假设你想处理每种情况下可能会省略两个字母,在URL的最后一部分中有17个字符,在272种组合中,虽然可能可以匹配多个“错误”的URL与一个正则表达式,但你仍需要大量的重写规则。

更好的解决方案是使用PHP(因为在问题中包含了该标记)实现404处理程序,生成一个列表,其中包含与所请求路径的最短Levenstein距离相对应的前10个URL的路径,并提供默认链接和支持文本。(有基于mysql的实现-尝试谷歌URL)。NB处理程序仍应返回404状态-NB HTML内容必须超过最小长度才能抑制MSIE的“友好”错误消息。


+1.. 我正想自己写这个.. 或许可以在 MySQL 层面上使用 SOUNDEX 来查找相似的 URL。或者 SELECT * FROM pages WHERE pageUrl SOUNDS LIKE userEnteredUrl - bummzack

7
如果你知道可能正确的URL,你可以使用以下方法:levenshtein($给定URL, $可能URL)
以下是来自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";

输出:

输入单词:carrrot
您想说的是:carrot?

当您认为人们可能省略了一个字母或多加了一个字母时,这很好,但当人们真正不知道如何拼写一个单词并想出了一些有创意的东西时,它可能会有所不足!

如果您更喜欢使用soundex()路线,请查看metaphone()函数。

我喜欢使用metaphone()levenshtein()similar_text()的想法,因为它返回单词的语音表示,并且您仍然希望看到它与原始单词有多相似。

例子:

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

虽然很多拼写错误都会返回相同的匹配,但最后一个示例表明您仍然希望使用类似于levenshtein()的东西来找到最接近的匹配。
为了提高效率,如果您使用不同的404文件进行重写以匹配此模式并失败,而不是用于站点的其余部分,则实际上不应该产生巨大开销。
如果您从同一引荐者处频繁收到相同的404(并且无法让他们更改链接),那么可能值得为该情况放置静态重写。

4

有几个解决方案:

  • 找出错误URL的源头。这种情况不应该发生,我无法想象为什么会发生。其他人是否从其他地方链接并制造了一个错别字(忽略了复制和粘贴的存在)?你能看到它来自哪里(referer)并联系他们吗?
  • 在URL中添加ID,例如/action/123/story-name-action,通过ID而不是标题查找文章(奖励:添加了使用相同标题创建多个相同类别故事的可能性)。
  • 对标题进行模糊搜索,使用类似soundex的东西,并将用户重定向到最合适的标题或显示具有类似标题的概述页面,就像@symcbean建议的那样。

我更喜欢ID。


1
我们针对像这样的URL设置了重定向到搜索页面 - 我们的搜索具有“建议”功能。

0

由于值(可能)是基于标题从MySQL中提取的,因此您可以在标题列上放置FULLTEXT索引,并使用MySQL的MATCH()函数查找最相关的匹配项,并将用户重定向到该匹配项。

尽管这绝不是完美的解决方案 - 要以任何真正准确度的方式执行此操作所需的智能类型已经接近Turing test领域。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接