Apache URL 重写无法正常工作

Posted

技术标签:

【中文标题】Apache URL 重写无法正常工作【英文标题】:Apache URL Re-writing not functioning properly 【发布时间】:2012-11-13 12:10:57 【问题描述】:

我正在尝试使用 apache-rewrite 规则来转换以下 URL:

http://localhost/foo/bar/news.php?id=24

转成这种格式:

http://localhost/foo/bar/news/foo-bar

数字 24mysql 表中随机行的 id,其中还包含 titlecontent 字段。

MariaDB [blog]> select * from articles;
+----+---------+----------+ 
| id | title   | content  |
+----+---------+----------+ 
|  1 | foo-bar | bla bla  | 
+----+---------+----------+ 
1 row in set (0.00 sec)

我的.htaccess 中有以下规则:

RewriteEngine On
RewriteCond %REQUEST_FILENAME !-d
RewriteCond %REQUEST_FILENAME !-f
RewriteCond %REQUEST_FILENAME !-l
^news/([A_Za_z0_9_]+)$ DIRECTORY/AID/news.php?id=$1 [QSA,L]

我还有一个 php 代码可以生成这样的链接:

$link = "<a href='news.php?id=$row['id']'></a>";
echo $link;  

但是,我无法获得重写规则来将路径更改为所需的最终结果。

【问题讨论】:

检查您的 apache 访问日志并查看它正在将其重写为什么,因为它是空白的,这意味着它正在访问 news.php 文件,但有些东西解析不正确。检查日志中的 PHP 错误。 你的应用程序的根是网络服务器的根吗?任何子文件夹?试试在第二行添加“RewriteBase /”吧? 在xampp控制面板上点击explore然后打开apache文件夹,然后logs文件夹然后查找php错误日志。 将 RewriteBase 指向 webapp 的根文件夹。所以它会像 RewriteBase /DIRECTORY/AID mhm,我忘了在末尾添加一个斜杠:RewriteBase /DIRECTORY/AID/ ? 【参考方案1】:

替换(真实)URL 有一个数字 -Code- 来标识链接(根据您的描述):http://localhost/DIRECTORY/AID/news.php?news=42

在这种情况下,该代码是 42,但您要显示的 URL 没有它。如果没有这个数字,我们总是会收到错误 404。这就像只输入:http://localhost/DIRECTORY/AID/news.php?news=

例如,必须通过在“/”后添加代码来修改要显示的 URL。可以是连字符等,但正则表达式必须相应修改。

这是一个示例,输入:http://localhost/news/42/ 以转到 http://localhost/DIRECTORY/ AID/news.php?news=42

RewriteEngine On
RewriteRule ^news/([0-9]+)/?$ DIRECTORY/AID/news.php?news=$1 [NC,L]

这就是你所需要的。要测试此示例,请在 http://localhost/DIRECTORY/AID/

news.php 中插入此唯一代码
<?php
if ( $_GET[ 'news' ] == '42' ) 
  echo  "HERE I AM<br /><br />";

?>

根据 OP 描述更新。可以使用任何名称代替 This_is_news

RewriteEngine On
RewriteRule ^news/([0-9a-zA-Z-_]+)/?$ DIRECTORY/AID/news.php?news=$1 [NC,L]

【讨论】:

但是这个例子是有效的。使用本地服务器进行测试可能会很棘手,您可能需要上传以进行测试。 Meanhile:¿您将 .htaccess 文件放在哪里? ¿ 还有其他 .htaccess 文件吗? ¿ localhost 目录结构到底是什么? ¿ DIRECTORY 是子目录还是根目录? 好像没问题,除了路径中的include目录。最好的办法是将 .htaccess 文件与 news.php 一起上传,并使用我的示例中的代码进行测试。 是的。确保将 .htaccess 放在“/DIRECTORY/”上方的目录中,并且路径中没有任何其他.htaccess 文件。 我已将文件上传到。 www.beminet.com news.php 和 .htaccess 检查一下,什么都没有 查看此链接。我将它上传到我的测试站点并且它正在工作:link。真正的 URL 是 falameda.com/DIRECTORY/AID/news.php?news=42【参考方案2】:

首先,您需要更改 html 中的 href,以提供新的 url 格式

function news_preview() 
$query = "SELECT * FROM news ORDER BY id DESC LIMIT 5  ";
$result = mysql_query($query) or die(mysql_error());
while($row=mysql_fetch_array($result)) 
   
  echo "<a href=\"/news/$row[id]\">  ". substr($row['title'], 0,26)."...</a><br/>".; 

会生成像http://localhost/news/24这样的url

请注意,我从 url 中删除了 /DIRECTORY/AID,因为 htaccess 建议您希望它是 url,而不是您在文本中所说的。

但现在可以访问http://localhost/news/this_is_article_title 类型的网址。因为this_is_article_title 和 id 24 之间没有相关性,所以实现这一点的唯一方法是将 id 也添加到 url,或者让 php 在数据库中查找具有此标题的新闻文章。

然而,最后一个解决方案存在一些问题,因为您不能只使用 url 中的标题。你必须转义字符。此外,您还必须为数据库中的标题行添加索引以获得更好的性能。

所以我将采用第一个解决方案。我们将生成这样的 url

http://localhost/news/24/this_is_article_title

首先是php部分

function news_preview() 
$query = "SELECT * FROM news ORDER BY id DESC LIMIT 5  ";
$result = mysql_query($query) or die(mysql_error());
while($row=mysql_fetch_array($result)) 
 
  $url = "/news/$row[id]/".preg_replace('/[^a-zA-Z0-9-_]/', '_', $row['title']);  
  echo "<a href=\"$url\">  ". substr($row['title'], 0,26)."...</a><br/>".; 

接下来是 htaccess 部分。

RewriteEngine On
RewriteCond %REQUEST_FILENAME !-d
RewriteCond %REQUEST_FILENAME !-f
RewriteCond %REQUEST_FILENAME !-l
RewriteRule ^news/([0-9]+)/([A-Za-z0-9_-]+)$ DIRECTORY/AID/news.php?id=$1 [QSA,L]

我认为应该这样做。

【讨论】:

+1 这种方法对我来说更有意义(拥有清晰可读的 url 比查询字符串数字要好得多)。但是我认为 RegExp 应该是 A-Za-z0-9_- 而不是 A_Za_z0_9-_ @pebbl 不错。在编写代码时,我一定非常喜欢我的 shift 键。厄立特里亚;请检查上面编辑的 htaccess 代码。 我忘了把RewriteRule 放在正则表达式之前。这有多蠢? 我认为这最终可以解决我的问题。我将 php 函数放在我的 index.php 中并修改了 .htaccess 文件。现在,当我将鼠标悬停在index.php 页面中回显的titles 上时,我可以在浏览器底部看到它将带我去哪里。它显示了localhost/news/24/this_is_titleIt【参考方案3】:

在 RewriteEngine On 之后放置 RewriteBase 它会在您开始重定向之前正确设置重写引擎

【讨论】:

好吧,我添加了你的建议,但我收到内部服务器错误 我可以看看它现在的样子吗? 42 和 46 是一样的,我有 id 1-100 的新闻 我想看看 .htaccess 的样子。很抱歉让您感到困惑 请注意 RewriteBase 需要的参数(您的基本路径)。它应该看起来 RewriteBase /DIRECTORY/AID/ 只需添加正确的路径【参考方案4】:

很遗憾,我无法在 PHP 或 Apache 中回答您的问题(尽管我正在使用手动 REST 转换器在我当前的项目中创建 URL 地址),但据我了解,您希望您的用户输入http://localhost/DIRECTORY/AID/article.php?a_id=24 并且地址栏应该像 http://localhost/DIRECTORY/AID/news/this_is_article_title强>.

我不完全确定这会给您带来什么好处,请记住,我的解决方案不允许您的最终用户键入 RESTful URL 并最终进入带有 QueryString 地址的页面。您需要做一些额外的工作才能做到这一点,甚至需要更多的工作才能使其与数据库保持同步(我建议使用一个脚本来定义 RESTFUL URL,在数据库中查询主题,然后返回 ID 或页面内容。 .. 但这是另一天的另一个 Stack Overflow 问题。

解决方案 我提出的解决方案需要 HTML5 doctype 和 very light 少量的 javascript

history.replaceState(null, "history title here", "news/this_is_article_title");

这样做的目的是更改地址栏中的 URL,而不会触发页面重定向、重新加载或其他任何操作。这个 javascript 可以用您的 PHP 动态编写,以便在提供页面时更新地址。文档中的位置越高,更改越快。

这是一个 jsFiddle 链接:http://jsfiddle.net/uT3RP/1/

不幸的是,他们在 iframe 中运行代码,因此它无法控制主地址栏,因此我添加了一个警报,显示地址栏位置会说什么,以供证明。这不是最优雅的解决方案。如果没有确保显示的 URL 可用于访问同一页面的故障保险,我什至不建议您做您正在做的事情。免责声明...您的问题通过 1 行 js 和 doctype 更改(如果您不使用 HTML5)解决。

你可以停止鞭打可怜的 ol' htaccess 并继续你的项目:)

【讨论】:

【参考方案5】:

这是关于 URL-Rewrite 和 String-to-Id 算法的问题。

最重要的是,请记住,无论你的 url 通过 rewrite 模块发生什么变化,浏览器栏中的 url 总是包含像 id 或字符串这样的帖子参数(关于你的新闻)。

现在回答问题。我们的目的只是重写Url:

http://localhost/DIRECTORY/AID/news/this_is_article_title

到:

http://localhost/DIRECTORY/AID/news.php?a_id=24

使用重写模块,我们只能将其重写为:

http://localhost/DIRECTORY/AID/news.php?title=this_is_article_title

这里是 htaccess 部分,已经在 htaccess-online-tester 上测试过

RewriteRule ^DIRECTORY/AID/news/([A-Za-z0-9_]+)$ DIRECTORY/AID/news.php?title=$1 [QSA,L]

剩下的工作是构建一个算法,将标题映射到重写模块无法帮助我们的新闻(尤其是你手动一个一个地重写 url)。我们可以使用下面的php代码:

<?php

//write url reflect to news title.
function build_news_url_by_title()
    $query = "SELECT * FROM news ORDER BY id DESC LIMIT 5";
    $result = mysql_query($query) or die(mysql_error());
    while($row = mysql_fetch_array($result))
        echo "<a href=\"news/".strtr(substr($row['title'], 0,26), " ", "_")."\">".substr($row['title'], 0,26)."</a>";
       


function get_news_by_title($title)
    $real_title = strtr($title, "_", " ");
    $query = "SELECT * FROM news WHERE title LIKE %".$real_title."% LIMIT 1";
    return mysql_query($query) or die(mysql_error());


$title = $_POST['title'];

$news = get_news_by_title($title);

//some code return the news
...

所以网址:

http://localhost/DIRECTORY/AID/news/this_is_article_title

也可以给我们消息。

最后,从上面的步骤中,如果我们输入url

http://localhost/DIRECTORY/AID/news/this_is_article_title

在浏览器栏中,也可以给我们消息。它与愚蠢的ID无关。尽管上面的代码可能存在一些错误,但请不要将其放在您的产品服务器上。

【讨论】:

【参考方案6】:

你能看看这是否有效吗?

RewriteEngine On
RewriteBase /DIRECTORY/AID/
RewriteCond %REQUEST_FILENAME !-d
RewriteCond %REQUEST_FILENAME !-f
RewriteCond %REQUEST_FILENAME !-l
^news/([A-Za-z0-9_]+)$ news.php?id=$1 [QSA,L]

编辑:修正了正则表达式字符类定义。

【讨论】:

【参考方案7】:

您缺少 URL 的标题。如果您希望在 URL 中显示,那么您也必须在链接中包含它,如下所示:

<a href="news.php?news_id=$id&title=$url_tile">

【讨论】:

【参考方案8】:

这似乎是一个复杂的问题,因为你不知道它到底在哪里做错了。

我建议您将您想做的事情分成小部分,并在将它们组合在一起之前使它们各自正常工作。例如:

 1. Make sure .htaccess file is readable and can do some simple thing, preventing directory indexing for instance.
 2. Make sure you can redirect something with simple html code.
 3. Make sure you can run Felipe's example code successfully. From here you can get good picture of what is going on. 

附带说明:

这样重写比较常见:

http://localhost/DIRECTORY/AID/news.php?a_id=24 TO -->
http://localhost/DIRECTORY/AID/news/24_this_is_article_title 

请注意,id 24 仍会转移到重写后的 url。这将使模式匹配更简单,并避免不必要的标题重复处理。

【讨论】:

【参考方案9】:

更改链接:

echo "<a href=\"news.php?news=$row[id]\"> ". substr($row['title'], 0,26)."</a>

echo "<a href=\"news/$row['title']\">".$row['title']."</a>"

这样,链接将转到news/$row['title'] 而不是news.php?id=...。现在在页面DIRECOTORY/AID/news.php,你应该得到id并检查它是否是一个数字OR文本,如果是文本,将它与$row['title']匹配,然后加载相应的页面。

注意事项:

    这假定 $row['title'] 在所有其他行中是唯一的。 标题不包含非 HTML 内容,在这种情况下,您必须对这些字符进行 URL 转义。

如果标题不是唯一的,那么您可能应该使用news/id/title,然后将其重写为DIRECTORY/AID/news.php?id=id&amp;title=title,然后您可以根据 ID 而不是标题。

希望对您有所帮助。

【讨论】:

改成"&lt;a href=\"news/$row[title]\"&gt;"看看能不能用。【参考方案10】:

如果您觉得您的 .htaccess 文件未按预期工作,则这是服务器配置问题,很可能与 Apache 配置下的 AllowOverride 指令有关。

在您的 http.conf 文件中找到如下所示的部分:

<Directory>
    Options FollowSymLinks
    AllowOverride None
</Directory>

AllowOverride 指令更改为允许All

<Directory>
    Options FollowSymLinks
    AllowOverride All
</Directory>

接下来要确保为您的 XAMPP 安装启用了 mod_rewrite 模块。搜索以下行:

#LoadModule rewrite_module modules/mod_rewrite.so

删除#,使其看起来像这样:

LoadModule rewrite_module modules/mod_rewrite.so

在保存所有更改后重新启动 Apache 服务

同时确保您在.htaccess 配置中使用RewriteBase 指令,如下所示:

RewriteEngine On
RewriteBase /DIRECTORY/AID/
RewriteCond %REQUEST_FILENAME !-d
RewriteCond %REQUEST_FILENAME !-f
RewriteCond %REQUEST_FILENAME !-l
^news/([A-Za-z0-9_]+)(/)?$ news.php?title=$1 [QSA,L]

接下来是确保您的链接指向重写 URL。您的回声线应类似于以下内容:

echo "<a href=\"news/" . $row['title'] . "\">  " . substr($row['title'], 0, 26) . "...</a><br />";

现在,由于您只能使用此 URL 重写方法检索标题,我们需要相应地配置您的 PHP 脚本以根据标题检索内容。如果您仍然只想使用“id”来检索记录,那么您的 Rewrite URL 应该以某种形式包含“id”。这种形式的典型例子是:

news/the_news_title_123 news/123_the_news_title news/123/the_news_title

【讨论】:

【参考方案11】:

我无法发表评论,所以我必须回答。

阅读所有答案和您的问题,不清楚您想要什么。至少对我来说。你说,例如:

http://localhost/DIRECTORY/AID/article.php?a_id=24

http://localhost/DIRECTORY/AID/article/this_is_article_title

但我想这不太对,除非你愿意

http://localhost/DIRECTORY/AID/article.php?a_id=24

作为在浏览器地址栏中输入的 URL,如果是,重定向的目的是什么?最后,任何访问者都必须准确地输入您不希望他们输入的内容。

我的猜测是您希望输入友好的 URL:

http://localhost/DIRECTORY/AID/article/this_is_article_title ,所以问题应该反过来:

http://localhost/DIRECTORY/AID/article/this_is_article_title

http://localhost/DIRECTORY/AID/article.php?a_id=24

接下来似乎不太清楚的是,浏览器栏中显示的内容是什么?唯一的答案是:输入的 URL。没有办法显示任何不同的东西。

简而言之:如果您希望 http://localhost/DIRECTORY/AID/article/this_is_article_title 显示在地址栏中,那就是您必须输入的内容。真正的 URL,即 SUBSTITUTION (http://localhost/DIRECTORY/AID/article.php?a_id=24),从未显示,也从未输入。这就是重定向的用途。

另一方面,也不清楚 news.php 提供的 ID 号如何被转换为像 article/this_is_article_title 这样的字符串。 ¿ 这些字符串在哪里,有多少个 ID 号,应该使用哪种算法或公式来实现该转换,这些 ID 中的哪些是您在评论中提到的“根”以及如何识别它们等?您应该详细说明这一点,因为它似乎与您以前的 cmets 即兴并不一致。

当然,我可能错了。我只是想尝试帮助您解决问题。

请,天才们,不要对这个答案投反对票,阅读它。我不是要回答这个问题,而且我离天才还差得很远。

【讨论】:

我不知道该告诉你什么,伙计。您的评论比问题更令人困惑。我虽然说得很清楚,但请再看一遍问题。它是不言自明的,我将对其进行更新以使其更加彻底。 好的,我已经纠正了我在路上犯的一些错误。请立即查看【参考方案12】:

看起来你忘记了“news.php”前面的斜线。

【讨论】:

以上是关于Apache URL 重写无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章

重写url wordpress无法正常工作

Apache %REQUEST_URI 无法正常工作

mod_rewrite 已安装但无法正常工作

Apache URL重写规则

重写为 MVC 后 GUI 无法正常工作

Discord.py 重写 - @has_permissions 无法正常工作