Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/.htaccess/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Apache 参考:mod_重写、URL重写和“漂亮链接”解释_Apache_.htaccess_Mod Rewrite_Friendly Url_Regex - Fatal编程技术网

Apache 参考:mod_重写、URL重写和“漂亮链接”解释

Apache 参考:mod_重写、URL重写和“漂亮链接”解释,apache,.htaccess,mod-rewrite,friendly-url,regex,Apache,.htaccess,Mod Rewrite,Friendly Url,Regex,漂亮的链接是一个经常被要求的话题,但很少有人对它进行充分的解释。是创建漂亮链接的一种方法,但它很复杂,语法非常简洁,很难理解,文档假定对HTTP有一定的熟练程度。有人能简单地解释一下漂亮的链接是如何工作的,以及如何使用mod_rewrite来创建它们吗 其他常用名称、别名、干净URL的术语:URL、用户友好URL、-友好URL和MVC URL可能用词不当要了解web服务器的工作原理,首先需要了解什么是mod_rewrite。web服务器响应。最基本级别的HTTP请求如下所示: GET /foo/

漂亮的链接是一个经常被要求的话题,但很少有人对它进行充分的解释。是创建漂亮链接的一种方法,但它很复杂,语法非常简洁,很难理解,文档假定对HTTP有一定的熟练程度。有人能简单地解释一下漂亮的链接是如何工作的,以及如何使用mod_rewrite来创建它们吗


其他常用名称、别名、干净URL的术语:URL、用户友好URL、-友好URL和MVC URL可能用词不当

要了解web服务器的工作原理,首先需要了解什么是mod_rewrite。web服务器响应。最基本级别的HTTP请求如下所示:

GET /foo/bar.html HTTP/1.1
GET /foo/bar?baz=42 HTTP/1.1
RewriteRule ^/myblog/(*.)$ /blog/$1 [R=301,QSA,L]
RewriteRule my-blog/entry.php?id=(\d+) my-blog/$1--i-found-the-answer [R]
这是浏览器向web服务器发出的简单请求,请求URL/foo/bar.html。需要强调的是,它不请求文件,它只请求一些任意的URL。请求也可能如下所示:

GET /foo/bar.html HTTP/1.1
GET /foo/bar?baz=42 HTTP/1.1
RewriteRule ^/myblog/(*.)$ /blog/$1 [R=301,QSA,L]
RewriteRule my-blog/entry.php?id=(\d+) my-blog/$1--i-found-the-answer [R]
这和URL请求一样有效,更明显的是,它与文件无关

web服务器是一个侦听端口的应用程序,它接受来自该端口的HTTP请求并返回响应。web服务器完全可以自由地以其认为合适的任何方式响应任何请求/以您配置的任何方式响应。这个响应不是一个文件,它是一个HTTP响应,它可能与任何磁盘上的物理文件有关,也可能与之无关。web服务器不必是Apache,还有许多其他web服务器都是持久运行的程序,连接到响应HTTP请求的端口。你可以自己写一本。这一段的目的是让你不再认为URL直接等于文件,这一点理解起来非常重要

大多数web服务器的默认配置是查找与硬盘上的URL匹配的文件。如果服务器的文档根被设置为,比如说,/var/www,它可能会查看文件/var/www/foo/bar.html是否存在,如果存在,则为其提供服务。如果文件以.php结尾,它将调用php解释器,然后返回结果。所有这些关联都是完全可配置的;文件不必以.php结尾,web服务器就可以通过php解释器运行它,URL也不必匹配磁盘上的任何特定文件

mod_rewrite是重写内部请求处理的一种方法。当web服务器收到URL/foo/bar的请求时,您可以将该URL重写为其他URL,然后web服务器将在磁盘上查找与之匹配的文件。简单的例子:

RewriteEngine On
RewriteRule   /foo/bar /foo/baz
此规则表示,只要请求与/foo/bar匹配,就将其重写为/foo/baz。然后,将处理该请求,就像请求了/foo/baz一样。这可以用于各种效果,例如:

RewriteRule (.*) $1.html
此规则匹配任何内容。*并捕获它..,然后将其重写为append.html。换句话说,如果/foo/bar是请求的URL,那么它将被处理为请求了/foo/bar.html。有关正则表达式匹配、捕获和替换的详细信息,请参阅

另一个经常遇到的规则是:

RewriteRule (.*) index.php?url=$1
这同样会匹配任何内容,并将其重写为index.php文件,并在URL查询参数中附加最初请求的URL。也就是说,对于任何和所有传入的请求,都会执行index.php文件,并且该文件将有权访问$_GET['url']中的原始请求,因此它可以用它做任何事情

主要是将这些重写规则放入web服务器配置文件中。Apache还允许*您将它们放入文档根目录中名为.htaccess的文件中,即.php文件旁边

*如果主Apache配置文件允许;它是可选的,但通常是启用的

mod_重写没有做什么 mod_rewrite并不能神奇地让你所有的URL变得漂亮。这是一个常见的误解。如果您的网站中有此链接:

<a href="/my/ugly/link.php?is=not&amp;very=pretty">
mod_rewrite无法让它变得漂亮。要使此链接美观,您必须:

将链接更改为漂亮链接:

<a href="/my/pretty/link">
在服务器上使用mod_rewrite,使用上述任何一种方法处理对URL/my/pretty/link的请求

可以结合使用来转换传出的HTML页面及其包含的链接。虽然这通常比更新HTML资源更费劲

mod_rewrite可以做很多事情,您可以创建非常复杂的匹配规则,包括链接多个重写,将请求代理到完全不同的服务或机器,返回特定的HTTP状态码作为响应,重定向请求等。它非常强大,如果您了解基本的HTTP请求-响应机制,就可以很好地使用它。它不会自动让你的链接变得漂亮

有关所有可能的标志和选项,请参见。

要进一步展开,我想提供一些som示例和说明 e其他模块重写功能

以下所有示例都假设您已经在.htaccess文件中包含了RewriteEngine On

重写示例 让我们举一个例子:

RewriteRule ^blog/([0-9]+)/([A-Za-z0-9-\+]+)/?$ /blog/index.php?id=$1&title=$2 [NC,L,QSA]
该规则分为4个部分:

# Apache 2.2
RewriteLogLevel 5
RewriteLog /tmp/rewrite.log

# Apache 2.4
LogLevel alert rewrite:trace5
#ErrorLog /tmp/rewrite.log
重写规则-启动重写规则 ^blog/[0-9]+/[A-Za-z0-9-\+]+/?$-这称为模式,但我将其称为规则的左侧-您要从中重写的内容 blog/index.php?id=$1&title=$2-称为替换,或重写规则的右侧-您要重写的内容 [NC、L、QSA]是重写规则的标志,用逗号分隔,稍后我将详细解释 上面的重写将允许您链接到像/blog/1/foo/这样的东西,它实际上会加载/blog/index.php?id=1&title=foo

规则的左边 ^指示页面名称的开头-因此它将重写example.com/blog/。。。但不是example.com/foo/blog/。。。 每一组…括号表示一个正则表达式,我们可以将其作为规则右侧的变量捕获。在本例中: 第一组括号-[0-9]+-匹配长度至少为1个字符且仅具有数字值(即0-9)的字符串。可以在规则的右侧用$1引用 第二组括号与长度至少为1个字符的字符串相匹配,该字符串仅包含字母数字字符a-Z、a-Z或0-9或-或+注意+用反斜杠转义,因为如果不转义,则将作为一个字符串执行。可以在规则的右侧用$2引用 ? 表示前面的字符是可选的,因此在本例中,/blog/1/foo/和/blog/1/foo都将重写到相同的位置 $表示这是要匹配的字符串的结尾 旗帜 这些选项添加在重写规则末尾的方括号中,用于指定特定条件。同样,有许多不同的标志,您可以在中阅读,但我将介绍一些更常见的标志:

NC
no case标志表示重写规则不区分大小写,因此对于上面的示例规则,这意味着/blog/1/foo/和/blog/1/foo/或其任何变体都将匹配

L
最后一个标志表示这是应处理的最后一条规则。这意味着,当且仅当此规则匹配时,将不会在当前重写处理运行中计算其他规则。如果规则不匹配,则将按正常顺序尝试所有其他规则。如果未设置L标志,则随后将对重写的URL应用以下所有规则

END
由于Apache2.4,您还可以使用[END]标志。与之匹配的规则将完全终止进一步的别名/重写处理。而[L]标志通常会触发第二轮,例如在重写子目录时

QSA
查询字符串append标志允许我们将额外的变量传递到指定的URL,该URL将被添加到原始get参数中。对于我们的示例,这意味着像/blog/1/foo/?comments=15这样的内容将加载/blog/index.php?id=1&title=foo&comments=15

这个标志不是我在上面的示例中使用的标志,而是我认为值得一提的标志。这允许您指定http重定向,并可选择包括状态代码,例如R=301。例如,如果您想在/myblog/to/blog/上执行301重定向,只需编写如下规则:

GET /foo/bar.html HTTP/1.1
GET /foo/bar?baz=42 HTTP/1.1
RewriteRule ^/myblog/(*.)$ /blog/$1 [R=301,QSA,L]
RewriteRule my-blog/entry.php?id=(\d+) my-blog/$1--i-found-the-answer [R]
重写条件 使重写功能更加强大,允许您为更具体的情况指定重写。您可以在中了解到许多情况,但我将介绍一些常见的示例并加以解释:

# if the host doesn't start with www. then add it and redirect
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
这是一种非常常见的做法,它会在你的域名前面加上www。如果它还没有出现,就执行301重定向。例如,加载http://example.com/blog/ 它会将你重定向到http://www.example.com/blog/

这稍微不太常见,但这是一个很好的示例,说明如果文件名是服务器上存在的目录或文件,则不会执行该规则

%{REQUEST_URI}\.jpg | jpeg | gif | png$[NC]将仅对文件扩展名为jpg、jpeg、gif或png的文件执行重写,不区分大小写。 %{请求文件名}-f将检查文件是否存在于当前服务器上,并且仅在文件不存在时执行重写 %{请求文件名}-d将检查文件是否存在于当前服务器上,并且仅在文件不存在时执行重写 重写将尝试在另一个域上加载相同的文件 mod_重写的替代方案 许多基本的虚拟URL方案都可以在不使用重写规则的情况下实现。Apache允许在不使用.PHP扩展名的情况下调用PHP脚本,并使用虚拟路径_INFO参数

用这个,卢克 现在通常默认情况下启用。它基本上允许.php和其他资源URL携带虚拟参数:

http://example.com/script.php/virtual/path
现在这个/virtual/path在PHP中显示,您可以在这里处理任何额外的参数 你喜欢什么就吃什么

这不如让Apache将输入路径段分成$1、$2、$3并将它们作为不同的$\u GET变量传递给PHP那么方便。它只是用更少的配置工作模拟漂亮的URL

启用以隐藏.php扩展名 在URL中避免使用.php文件扩展名的最简单选项是启用:

Options +MultiViews
由于匹配的basename,这使得/article上的HTTP请求具有Apache select article.php。这与前面提到的PATH_INFO特性配合得很好。所以你可以像这样使用URLhttp://example.com/article/virtual/title. 如果您有一个具有多个PHP调用点/脚本的传统web应用程序,这是有意义的

但请注意,多视图有一个不同/更广泛的用途。它会带来非常小的性能损失,因为Apache总是查找具有匹配基名称的其他文件。它实际上是为了,所以浏览器可以在可用资源中获得最佳选择,如article.en.php、article.fr.php、article.jp.mp4

无扩展.php脚本的SetType或SetHandler 避免在URL中携带.php后缀的更直接的方法是针对其他文件方案。最简单的选项是通过.htaccess覆盖默认MIME/处理程序类型:

通过这种方式,您可以将article.php脚本重命名为不带扩展名的just-article,但仍将其作为php脚本处理

现在,这可能会对安全性和性能产生一些影响,因为现在所有无扩展文件都将通过PHP管道传输。因此,您也可以仅为单个文件设置此行为:

<Files article>
  SetHandler application/x-httpd-php
  # or SetType 
</Files>
这在某种程度上取决于您的服务器设置和使用的PHP SAPI。常见的替代方案包括ForceType应用程序/x-httpd-php或AddHandler php5脚本

再次注意,此类设置会从一个.htaccess传播到子文件夹。对于静态资源和上载/目录等,应始终禁用脚本执行SetHandler None和选项-Exec或php_标志引擎off等

其他Apache重写方案 在众多选项中,Apache提供了mod_别名功能,有时这种功能与mod_重写规则一样有效。请注意,其中大多数必须在节中设置,而不是在每个目录的.htaccess配置文件中设置

主要用于CGI脚本,但也适用于PHP。它允许regexp就像任何重写规则一样。事实上,它可能是配置全面前端控制器的最健壮的选项

一个简单的代码也有助于一些简单的重写方案

甚至可以使用普通指令让PHP脚本处理虚拟路径。请注意,这是一个笨拙的解决方法,但是,它禁止GET请求以外的任何操作,并根据定义将error.log淹没

有关更多提示,请参阅

工具书类 Stack Overflow还有许多其他优秀资源可供使用:

请记住删除“^/pattern”前缀中的斜杠,以便使用.htaccess。 做和不做都在里面。 浏览我们的问题和答案。 阿帕奇指南。 阿斯卡帕奇 还有。 甚至对新来者友好的正则表达式概述:

我们需要一个语法概要。 还有短的。 还有一些简单易懂的基础知识。 常用占位符 *匹配任何内容,即使是空字符串。您不希望在任何地方都使用此模式,但通常在最后的回退规则中使用。 [^/]+更常用于路径段。它匹配除正斜杠以外的任何东西。 \d+仅匹配数字字符串。 \w+匹配字母数字字符。它基本上是[A-Za-z0-9]的简写。 [\w\-]+用于段塞式路径段,使用字母、数字、破折号和_ [\w\-,]+添加句点和逗号。喜欢[…]字符类中的转义符。 \.表示文字句点。否则[…]之外是任何符号的占位符。 这些占位符中的每一个通常都作为捕获组包装在…括号中。整个模式通常使用^………$start+end标记。引用模式是可选的

重写规则 以下示例是以PHP为中心的,并且更加增量,更易于适应类似情况。 它们只是总结,通常会链接到更多变体或详细的问答

静态映射/联系,/about 将几个页面名称缩短为内部文件方案最简单:

 RewriteRule ^contact$  templ/contact.html
 RewriteRule ^about$    about.php
数字标识符/object/123 引入快捷方式,如http://example.com/article/531 修改现有的PHP脚本也很容易。数字占位符可以重新映射到$\u GET参数:

 RewriteRule ^article/(\d+)$    article-show.php?id=$1
 #                      └───────────────────────────┘
Slug样式占位符/文章/带有一些标题Slug 您可以轻松扩展该规则以允许使用/article/title字符串占位符:

 RewriteRule ^article/([\w-]+)$    article-show.php?title=$1
 #                       └────────────────────────────────┘
请注意,您的脚本必须能够或经过调整以将这些标题映射回数据库ID。仅仅重写规则无法凭空创建或猜测信息

带数字前缀的slug/readable/123加标题 因此,您经常会看到实践中使用的混合/article/529 title slug路径:

 RewriteRule ^article/(\d+)-([\w-]+)$    article.php?id=$1&title=$2
 #                      └───────────────────────────────┘
现在你可以跳过传球了 title=$2,因为脚本通常依赖于数据库id。标题段塞已成为任意URL装饰

与备选列表的一致性/foo/../bar/../baz/… 如果您对多个虚拟页面路径有类似的规则,那么您可以使用|备选列表对它们进行匹配和压缩。再次将它们重新分配给内部GET参数:

 #                               ┌─────────────────────────┐
 RewriteRule ^(blog|post|user)/(\w+)$  disp.php?type=$1&id=$2
 #               └───────────────────────────────────┘
如果这变得太复杂,您可以将它们拆分为单独的重写规则

将相关URL分派到不同的后端/日期/交换机/后端 替代列表的一个更实际的用途是将请求路径映射到不同的脚本。例如,根据日期为较旧和较新的web应用程序提供统一的URL:

 #                   ┌─────────────────────────────┐
 #                   │                 ┌───────────┼───────────────┐
 RewriteRule ^blog/(2009|2010|2011)/([\d-]+)/?$ old/blog.php?date=$2
 RewriteRule ^blog/(\d+)/([\d-]+)/?$  modern/blog/index.php?start=$2
 #                          └──────────────────────────────────────┘
这只是将2009-2011年的帖子重新映射到一个脚本上,其他年份的帖子则隐式地映射到另一个处理程序上。 请注意,首先是更具体的规则。每个脚本可能使用不同的GET参数

除/path斜杠/user-123-name以外的其他分隔符 您通常会看到重写规则来模拟虚拟目录结构。但你并不是被迫缺乏创造性。您也可以使用-连字符进行分段或构造

 RewriteRule ^user-(\d+)$    show.php?what=user&id=$1
 #                   └──────────────────────────────┘
 # This could use `(\w+)` alternatively for user names instead of ids.
对于同样通用的/wiki:section:Page\u名称方案:

有时它适合在/-分隔符和:或之间交替使用。甚至在同一条规则中。或者再次使用两个重写规则将变体映射到不同的脚本

可选尾随/斜杠/dir=/dir/ 选择目录样式路径时,可以使用或不使用最终路径使其可访问/

现在,这可以处理这两个问题http://example.com/blog/123 和/blog/123/。/?$方法很容易附加到任何其他重写规则上

虚拟路径的灵活段。*/*/.*/* 您将遇到的大多数规则将一组受约束的/../resource path段映射到各个GET参数。然而,有些脚本。 ApacheRegexp引擎不允许对任意数量的代码进行选项化。但您可以自己轻松地将其扩展为规则块:

 Rewriterule ^(\w+)/?$                in.php?a=$1
 Rewriterule ^(\w+)/(\w+)/?$          in.php?a=$1&b=$2
 Rewriterule ^(\w+)/(\w+)/(\w+)/?$    in.php?a=$1&b=$2&c=$3
 #              └─────┴─────┴───────────────────┴────┴────┘
如果最多需要五条路径段,请将此方案复制到五条规则中。当然,您可以分别使用更具体的[^/]+占位符。 在这里,排序并不重要,因为两者都不重叠。因此,首先使用最常用的路径是可以的

或者,您可以通过?p[]=$1&p[]=$2&p[]=3查询字符串在此处使用PHPs数组参数-如果您的脚本只希望它们预拆分。 尽管更常见的是只使用一个catch-all规则,并让脚本本身将这些段从请求URI中展开

另见:

可选段前缀/opt?/* 一个常见的变化是在规则中有可选的前缀。如果周围有静态字符串或更多受约束的占位符,这通常是有意义的:

  RewriteRule ^(\w+)(?:/([^/]+))?/(\w+)$  ?main=$1&opt=$2&suffix=$3
现在是更复杂的模式?:/[^/]+?这里简单地包装了一个非捕获的?:…组,并使其成为可选的?。控制 占位符[^/]+将是替换模式$2,但如果没有中间/../path,则为空

捕获余数/prefix/123 Capture/../../*/…无论什么… 如前所述,您通常不需要太通用的重写模式。然而,有时将静态和特定比较与。*结合起来是有意义的

 RewriteRule ^(specific)/prefix/(\d+)(/.*)?$  speci.php?id=$2&otherparams=$2
此选项将任何/../…/…尾随路径段个性化。当然,这需要处理脚本将其拆分,并对提取的参数进行变量化 Web MVC框架本身就是这样做的

尾部文件扩展名/old/path.HTML URL实际上没有文件扩展名。这就是整个参考的内容=URL是虚拟定位器,不一定是直接的文件系统映像。 但是,如果以前有1:1的文件映射,则可以制定更简单的规则:

 RewriteRule  ^styles/([\w\.\-]+)\.css$  sass-cache.php?old_fn_base=$1
 RewriteRule  ^images/([\w\.\-]+)\.gif$  png-converter.php?load_from=$2
其他常见用途是将过时的.html路径重新映射到较新的.php处理程序,或者仅为单个实际/真实文件别名目录名

乒乓球统一重定向和重写/sugger.html←→ /漂亮的 因此,在某个时候,你正在重写你的HTML页面,以便只携带漂亮的链接,如图所示。 同时,您仍然会收到对旧路径的请求,有时甚至来自书签。作为解决方法,您可以使用乒乓浏览器来显示/建立 新的URL

这种常见的技巧包括每当传入URL遵循过时/丑陋的命名方案时发送30x/Location重定向。 浏览器随后将重新请求新的/pretty URL,然后在内部将其重写到原始或新位置

 # redirect browser for old/ugly incoming paths
 RewriteRule ^old/teams\.html$ /teams [R=301,QSA,END]

 # internally remap already-pretty incoming request
 RewriteRule ^teams$ teams.php        [QSA,END]
请注意,此示例仅使用[END]而不是[L]来安全地进行替换。对于较旧的Apache2.2版本,除了重新映射之外,还可以使用其他解决方法 查询字符串参数,例如:

空间␣ 以模式/这个+那个+ 它在浏览器地址栏中并没有那么漂亮,但您可以在URL中使用空格。对于重写模式,使用反斜杠转义\␣ 空间。 否则,只需引用整个模式或替换:

 RewriteRule  "^this [\w ]+/(.*)$"  "index.php?id=$1"  [L]
客户端使用+或%20为空格序列化URL。但在规则中,它们是 使用所有相对路径段的文字字符进行解释

经常重复:

捕获a/front控制器脚本的所有内容 PHP框架或WebCM/portal脚本经常使用它。然后,在PHP中使用$\u SERVER[REQUEST\u URI]处理实际的路径拆分。所以从概念上讲,它与每次mod_重写的URL处理几乎相反。用它来代替

从主机名中删除www 请注意,这不会复制查询字符串等

 #                               ┌──────────┐
 RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]  │ 
 RewriteRule ^(.*)$ http://%1/$1 [R=301,L]  │
 #             ↓           └───┼────────────┘
 #             └───────────────┘
另见: · · ·

请注意,RewriteCond/RewriteRule组合可能更复杂,匹配项%1和$1在两个方向上交互,甚至:

版权所有2015 Apache软件基金会,AL 2.0版/P> 重定向到HTTPS:// 另见:

删除PHP扩展 另见:

将旧的.html路径别名为.php脚本 见:

将URL like/page重写为/index.php/page等脚本 看

将子域重定向到文件夹 看

普遍存在的访问陷阱 现在把这个和盐一起吃。并不是每个建议都可以推广到所有环境。 这只是对众所周知的几个不明显的障碍的简单总结:

启用mod_重写和.htaccess 要在每个目录配置文件中实际使用重写规则,您必须:

检查您的服务器是否已安装。否则,您的per directory.htaccess指令将被忽略,重写规则将不起作用

显然是在httpd.conf模块部分

在RewriteEngine仍然打开的情况下,在每个规则列表前加上前缀。虽然mod_rewrite在和节中处于隐式活动状态, 每个目录.htaccess文件需要单独调用它

前导斜杠^/不匹配 您不应使用^/启动.htaccess重写规则模式。通常情况下:

 RewriteRule ^/article/\d+$  …
              ↑
这在旧教程中经常出现。对于古老的Apache1.x版本来说,它过去是正确的。现在,在.htaccess规则中,请求路径可以方便地与目录完全相关。只需把前面的/不在前面

·请注意,尽管如此,前导斜杠在部分中仍然是正确的。这就是为什么你经常看到它^/?规则奇偶性的可选化。 ·或者在使用RewriteCond%{REQUEST_URI}时,您仍然可以匹配前导/。 ·另见

包装袋走开! 您可能已经在许多示例中看到了这一点:

<IfModule mod_rewrite.c>
   Rewrite… 
</IfModule>
默认情况下,它不会这样做。您可以使用[S=2]标志。否则你就得重复一遍。有时,您可以制定一个反向的主要规则,以便尽早[结束]重写处理

查询\免于重写规则的字符串 您无法匹配RewriteRule index.php\?x=y,因为mod_rewrite仅与每个默认值的相对路径进行比较。但是,您可以通过以下方式分别匹配它们:

 RewriteCond %{QUERY_STRING} \b(?:param)=([^&]+)(?:&|$)
 RewriteRule ^add/(.+)$  add/%1/$1  # ←──﹪₁──┘
另见

.htaccess vs。 如果在每个目录配置文件中使用RewriteRules,那么担心正则表达式的性能是毫无意义的。阿帕奇保留 编译的PCRE模式比具有公共路由框架的PHP进程长。然而,对于高流量的网站,你应该考虑 一旦经过作战测试,将规则集移动到vhost服务器配置中

在这种情况下,首选选项化的^/?目录分隔符前缀。这允许在PerDir和服务器之间自由移动重写规则 配置文件

不管什么时候出了问题 不要烦恼

比较access.log和error.log

通常,只要查看error.log和access.log,就可以了解重写规则的错误行为。 关联访问时间以查看最初进入的请求路径,以及Apache无法解析错误404/500的路径/文件

这并不能告诉你哪条规则是罪魁祸首。但是像/docroot/21-.itle?index.php这样无法访问的最终路径可能会泄露进一步检查的位置。 否则禁用规则,直到获得一些可预测的路径

启用重写日志

见文件。对于调试,您可以在vhost部分中启用它:

# Apache 2.2
RewriteLogLevel 5
RewriteLog /tmp/rewrite.log

# Apache 2.4
LogLevel alert rewrite:trace5
#ErrorLog /tmp/rewrite.log
这将生成每个规则如何修改传入请求路径的详细摘要:

[..] applying pattern '^test_.*$' to uri 'index.php'
[..] strip per-dir prefix: /srv/www/vhosts/hc-profi/index.php -> index.php
[..] applying pattern '^index\.php$' to uri 'index.php'
这有助于缩小过于通用的规则和正则表达式的失误

另见: · ·

在问你自己的问题之前

正如您可能知道的,堆栈溢出非常适合询问有关mod_重写的问题。制造它们 通过包括先前的研究和尝试,避免重复回答,展示基本理解,以及:

包括输入URL、错误重写的目标路径、真实目录结构的完整示例。 完整的重写规则集,但也挑出假定有缺陷的规则集。 Apache和PHP版本、操作系统类型、文件系统、文档根目录和PHPs$\服务器环境(如果与参数不匹配有关)。 从access.log和error.log中摘录,以验证现有规则的解析结果。更好的是,一个rewrite.log摘要。 这将得到更快、更准确的答案,并使它们对其他人更有用

评论你的.htaccess 如果您从某处复制示例,请注意包含注释和源链接。虽然这只是坏消息 安内斯省略了归属, 这经常会对以后的维护造成伤害。记录任何代码或教程源代码。尤其是在没有人的时候,你应该 更感兴趣的是不要把它们当作魔法黑匣子

这不是SEO URL 免责声明:只不过是一种恼怒。你经常听到漂亮的URL重写方案被称为SEO链接之类的。虽然这在谷歌搜索示例时很有用,但这是一个过时的误称

没有一个现代搜索引擎真正受到路径段中的.html和.php的干扰,或者?id=123查询字符串。旧的搜索引擎,如AltaVista,确实避免了爬行具有潜在模糊访问路径的网站。现代爬虫甚至经常渴望深度网络资源

从概念上讲,漂亮的URL应该用于使网站变得用户友好

具有可读性和明显的资源方案。 确保URL是长寿命的。 通过/common/tree/nesting提供可发现性。 但是,不要为了遵从而牺牲独特的要求

工具 有各种在线工具可以为大多数GET参数化URL生成重写规则:


大多数情况下,只输出[^/]+通用占位符,但对于普通站点可能就足够了。

关于URL重写的常见问题如下:

GET /foo/bar.html HTTP/1.1
GET /foo/bar?baz=42 HTTP/1.1
RewriteRule ^/myblog/(*.)$ /blog/$1 [R=301,QSA,L]
RewriteRule my-blog/entry.php?id=(\d+) my-blog/$1--i-found-the-answer [R]
我目前有如下URL:

GET /foo/bar.html HTTP/1.1
GET /foo/bar?baz=42 HTTP/1.1
RewriteRule ^/myblog/(*.)$ /blog/$1 [R=301,QSA,L]
RewriteRule my-blog/entry.php?id=(\d+) my-blog/$1--i-found-the-answer [R]
我把它们弄得这么漂亮:

GET /foo/bar.html HTTP/1.1
GET /foo/bar?baz=42 HTTP/1.1
RewriteRule ^/myblog/(*.)$ /blog/$1 [R=301,QSA,L]
RewriteRule my-blog/entry.php?id=(\d+) my-blog/$1--i-found-the-answer [R]
通过在my.htaccess文件中使用此选项:

RewriteRule my-blog/(\d+)--i-found-the-answer my-blog/entry.php?id=$1 
但我想让它们看起来像这样:

GET /foo/bar.html HTTP/1.1
GET /foo/bar?baz=42 HTTP/1.1
RewriteRule ^/myblog/(*.)$ /blog/$1 [R=301,QSA,L]
RewriteRule my-blog/entry.php?id=(\d+) my-blog/$1--i-found-the-answer [R]
如何更改.htaccess文件以使其正常工作

简单的答案是你不能

重写规则不会让丑陋的URL变得漂亮,而是让漂亮的URL变得丑陋 无论何时在web浏览器中键入URL、跟踪链接或显示引用图像的页面等,浏览器都会请求特定URL。该请求最终到达web服务器,web服务器给出响应

重写规则就是这样一个规则:当浏览器请求一个看起来像X的URL时,给他们与请求Y相同的响应

当我们制定规则来处理漂亮的URL时,请求就是漂亮的URL,响应基于内部丑陋的URL。它不能反过来,因为我们正在服务器上编写规则,服务器看到的只是浏览器发送的请求

你不能使用你没有的信息 考虑到重写规则的基本功能模型,想象一下您正在向一个人发出指令。你可以说:

如果您在请求中看到一个数字,如中的42http://example.com/my-blog/42-i-found-the-answer,将该数字放在我的blog/entry.php?id的末尾= 但是,如果请求中没有信息,您的指示将毫无意义:

如果请求中有我的博客,比如http://example.com/my-blog/i-found-the-answer,在我的blog/entry.php?id的末尾输入正确的数字= 阅读这些说明的人会说对不起,我怎么知道正确的数字是多少

重定向:此URL当前不在办公室。。。 有时,你会看到相反的规则,比如:

GET /foo/bar.html HTTP/1.1
GET /foo/bar?baz=42 HTTP/1.1
RewriteRule ^/myblog/(*.)$ /blog/$1 [R=301,QSA,L]
RewriteRule my-blog/entry.php?id=(\d+) my-blog/$1--i-found-the-answer [R]
这个规则在左边匹配一个丑陋的URL,在右边生成一个漂亮的URL。那么,我们肯定可以在漂亮部分的开头不带ID地写它

RewriteRule my-blog/entry.php?id=(\d+) my-blog/i-found-the-answer [R]
重要的区别是[R]标志,这意味着此规则实际上是一个重定向-它不是提供来自此URL的响应,而是告诉浏览器加载此URL

你可以把它想象成一封自动回复邮件,说对不起,乔·布洛格斯正在度假;请把你的信息转给简·史密斯。同样地,上面的重定向告诉浏览器抱歉,没有针对的内容http://example.com/my-blog/entry.php?id=42; 请要求http://example.com/my-blog/42-i-found-the-answer 相反

这个类比的重要一点是,如果实际上没有叫简·史密斯的人在那里工作,或者如果他们不知道如何回答乔·布洛格斯通常处理的问题,那么上述信息就没有多大用处。类似地,如果您告诉浏览器请求的URL实际上没有做任何有用的事情,那么重定向也没有用。一旦浏览器遵循重定向,它将发出一个新请求,当服务器收到新请求时,它仍然不知道ID号是什么

但是有些网站会这样做,所以这一定是可能的! web服务器只有请求中的信息,但如何使用这些信息取决于您

例如,您可以直接将其URL存储在数据库中,然后编写一些代码直接在PHP、Python、node.js等中进行匹配,而不是按ID查找博客文章。或者,您可以根据用户在浏览器中设置的语言或cookie等,让同一URL显示不同的内容

但是你不能在.htaccess文件中写一行就能创造奇迹。

也许可以将2.2.16版中引入的
重写到调度程序的过程。Slug或slaging是另一个常见的别名/术语,表示漂亮的URL。@Mike有点像,但Slug通常是漂亮URL的一部分。例如,当一篇文章的标题变成一个URL友好的形式,然后作为该文章的标识符时,slug就非常特别了。因此,reference mod rewrite url rewriting explained就是slug,/questions/20563772/reference mod rewrite url rewriting explained就是漂亮的url。我认为.htaccess和mod rewrite标签应该更新,以包含到这个问题的链接,因为它涵盖了很多定期询问的内容。想法?要学习Apache mod rewrite的一些基础知识,您可以学习这个简短的教程,它仍然需要一些重写、更多的链接,而且许多副标题有些令人讨厌。这里有一些与其他答案重叠的地方,所以可能可以减少。这主要是关于视觉上的例子,以及常见的陷阱列表。很久没有看到如此美丽的答案了!我读的时候眼睛闪闪发光。请不要停止发布这样的答案:非常好的帖子。让我很快理解了mod_rewrite的基本概念!