介绍
在本教程中,我们将激活并学习如何使用Apache2 mod_rewrite
模块管理URL重写。这个工具允许我们以更干净的方式重写URL,将人类可读的路径转换为代码友好的查询字符串。
本指南分为两部分:第一部分设置示例Web应用程序,第二部分解释常用的重写规则。
准备
- 一台已经设置好可以使用
sudo
命令的非root账号的Ubuntu 服务器,并且已开启防火墙。没有服务器的同学可以在这里购买,不过我个人更推荐您使用免费的腾讯云开发者实验室进行试验,学会安装后再购买服务器。
第1步 - 安装Apache
在此步骤中,我们将使用一个名为apt-get
的内置包安装程序。它大大简化了管理并简化了安装。
首先,更新系统的包索引。这将确保旧的或过时的包不会干扰安装。
代码语言:javascript复制sudo apt-get update
Apache2是前面提到的HTTP服务器,也是世界上最常用的。要安装它,请运行以下命令:
代码语言:javascript复制sudo apt-get install apache2
第2步 - 启用mod_rewrite
现在,我们需要激活mod_rewrite
。
sudo a2enmod rewrite
这将激活模块或提醒您模块已经生效。要使这些更改生效,请重新启动Apache。
代码语言:javascript复制sudo service apache2 restart
第3步 - 设置.htaccess
在本节中,我们将设置一个.htaccess
文件,以便进行更简单的重写规则管理。
一个.htaccess
文件可以让我们修改我们的重写规则,而无需访问服务器配置文件。因此,.htaccess
对Web应用程序的安全性至关重要。文件名之前的句点可确保隐藏文件。
在我们开始之前,我们需要设置并确保更多设置。
首先,允许更改.htaccess
文件。使用nano
或您喜欢的文本编辑器打开默认的Apache配置文件。
sudo nano /etc/apache2/sites-enabled/000-default.conf
在该文件中,您将在第1行找到该<VirtualHost *:80>
块。在该块的内部,添加以下块:
<Directory /var/www/html>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
</Directory>
您的文件现在应该与以下内容匹配。确保所有块都正确缩进。
代码语言:javascript复制<VirtualHost *:80>
<Directory /var/www/html>
. . .
</Directory>
. . .
</VirtualHost>
要使这些更改生效,请重新启动Apache。
代码语言:javascript复制sudo service apache2 restart
现在,创建.htaccess
文件。
sudo nano /var/www/html/.htaccess
在新文件的顶部添加第一行以激活RewriteEngine
。
RewriteEngine on
保存并退出该文件。
要确保其他用户只能读取您的用户.htaccess
,请运行以下命令以更新权限。
sudo chmod 644 /var/www/html/.htaccess
您现在有一个操作.htaccess
文件来管理Web应用程序的路由规则。
第4步 - 设置文件
在本节中,我们将设置一个基本的URL重写,它将漂亮的URL转换为代码的实际路径。具体来说,我们将允许用户访问example.com/about
。
我们将从创建一个名为的文件开始about.html
。
sudo nano /var/www/html/about.html
将以下代码复制到HTML页面。
代码语言:javascript复制<html>
<head>
<title>About Us</title>
</head>
<body>
<h1>About Us</h1>
</body>
</html>
您可以访问your_server_ip/about.html
或example.com/about.html
访问您的Web应用程序。现在注意到只有about.html
可访问; 如果您尝试访问your_server_ip/about
,则会收到Not Found错误。我们希望用户访问about
。我们的重写规则将允许这个功能。
打开.htaccess
文件。
sudo nano /var/www/html/.htaccess
在第一行之后,添加以下内容。
代码语言:javascript复制RewriteRule ^about$ about.html [NC]
您的文件现在应该与以下内容相同。
代码语言:javascript复制RewriteEngine on
RewriteRule ^about$ about.html [NC]
恭喜。您现在可以example.com/about
在浏览器中访问!
这是一个很好的简单示例,显示了所有重写规则遵循的一般语法。
^about$
是从URL匹配的字符串。也就是说,这是观众在她的浏览器中输入的内容。我们的示例使用了一些元字符。
example.com/
剥离后^
表示URL的开头。$
表示URL的结尾about
匹配字符串“约”
about.html
是用户访问的实际路径; 也就是说,Apache仍将提供该about.html
文件。
[NC]
是一个忽略URL中大写的标志。
使用上面显示的规则,以下URL将指向about.html
:
example.com/about
example.com/About
example.com/about.html
以下不会:
example.com/about/
example.com/contact
常见模式
在本节中,我们将展示一些常用的指令。
您的Web应用程序现在正在运行,并受受保护.htaccess
文件的约束。最简单的例子如上所述。我们将在本节中探讨另外两个示例。
如果您愿意,可以在结果路径中设置示例文件,但本教程不包括创建HTML和PHP文件; 只是重写的规则。
示例1:使用RewriteRule简化查询字符串
所有人都RewriteRule
遵循以下格式:
RewriteRule pattern substitution [flags]
- RewriteRule:指定指令
RewriteRule
- pattern:与所需字符串匹配的正则表达式
- substitution:实际URL的路径
- flags:可以修改规则的可选参数
Web应用程序通常使用查询字符串,这些字符串使用?
问号附加到URL 并使用&
&符号分隔。匹配重写规则时会忽略它们。但是,有时可能需要查询字符串来在页面之间传递数据。例如,用PHP编写的搜索结果页面可能会使用类似于以下内容的内容:
http://example.com/results.php?item=shirt&season=summer
在这个例子中,我们希望将其简化为:
代码语言:javascript复制http://example.com/shirt/summer
例1A:简单的替换
使用重写规则,我们可以使用以下内容:
代码语言:javascript复制/var/www/html/.htaccessRewriteRule ^shirt/summer$ results.php?item=shirt&season=summer
以上是相当不言自明的,因为它实际上映射shirt/summer
到results.php?item=shirt&season=summer
。这实现了我们期望的效果。
例1B:匹配选项
但是,我们想将此概括为包括所有季节。因此,我们将执行以下操作:
- 使用
|
布尔值指定一系列选项,意思是“OR” - 匹配使用组
()
,然后使用引用组$1
,与1
用于第一个匹配组
重写规则现在变为:
代码语言:javascript复制/var/www/html/.htaccessRewriteRule ^shirt/(summer|winter|fall|spring) results.php?item=shirt&season=$1
上面显示的规则匹配shirt/
指定季节后面的URL 。该季节使用分组()
,然后$1
在后续路径中引用。这意味着,例如,:
http://example.com/shirt/winter
变为:
代码语言:javascript复制http://example.com/results.php?item=shirt&season=winter
这也实现了期望的效果。
示例1C:匹配字符集
但是,我们还要指定任何类型的项目,而不仅仅是URL /shirt
。因此,我们将执行以下操作:
- 编写一个匹配所有字母数字字符的正则表达式。括号表达式
[]
匹配其中的任何字符,并 - 对匹配进行分组,并将其
$2
作为文件中的第二个变量引用
/var/www/html/.htaccessRewriteRule ^([A-Za-z0-9] )/(summer|winter|fall|spring) results.php?item=$1&season=$2
以上将转换,例如:
代码语言:javascript复制http://example.com/pants/summer
至:
代码语言:javascript复制http://example.com/results.php?item=pants&season=summer
示例1D:传递查询字符串
本节不介绍任何新概念,但解决了可能出现的问题。使用上面的示例,假设我们想重定向http://example.com/pants/summer
但会传递一个额外的查询字符串?page=2
。我们想要以下内容:
http://example.com/pants/summer?page=2
映射到:
代码语言:javascript复制http://example.com/results.php?item=pants&season=summer&page=2
如果您尝试使用我们当前的设置访问上述URL,您会发现查询字符串page=2
丢失了。使用附加QSA
标志可以轻松修复此问题。修改重写规则以匹配以下内容,并将实现所需的行为。
RewriteRule ^([A-Za-z0-9] )/(summer|winter|fall|spring) results.php?item=$1&season=$2 [QSA]
示例2:使用逻辑添加条件
RewriteCond
让我们为我们的重写规则添加条件。所有人都RewriteCond
遵循以下格式:
RewriteCond TestString Condition [Flags]
- RewriteCond:指定
RewriteCond
指令 - TestString:要测试的字符串
- 条件:匹配的模式
- 标志:可以修改条件的可选参数
如果RewriteCond
评估为true,RewriteRule
则将考虑紧随其后的内容。
例2A:默认页面
在假想的管理面板中,我们可能希望将所有格式错误的URL指向主页,而不是用404问候用户。使用条件,我们可以检查所请求的文件是否存在。
代码语言:javascript复制RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^admin/(.*)$ /admin/home
这将重定向像/admin/blargh
来/admin/home
。
有了上述:
%{REQUEST_FILENAME}
是要检查的字符串!-f
在文件名上使用!
not运算符RewriteRule
将所有请求重定向回/admin/home
请注意,在语法和技术上更正确的方法是定义404 ErrorDocument
。
ErrorDocument 404 /error.html
例2B:IP访问限制
虽然这也可以使用其他方法实现,但是RewriteCond
可以使用a来限制对一个IP或一组IP地址的访问。
此示例阻止来自除 12.34.56.789 之外的所有位置的流量。
代码语言:javascript复制RewriteCond %{REMOTE_ADDR} !^(12.34.56.789)$
RewriteRule (.*) - [F,L]
整个声明显示“如果地址不是 12.34.56.789,则不允许访问”。
简而言之:
%{REMOTE_ADDR}
是地址字符串!^(12.34.56.789)$``.
使用反斜杠转义所有句点并使用取消IP地址
!
- 该
F
标志禁止访问L
,如果执行,则该标志表示这是最后运行的规则
如果您宁愿阻止 12.34.56.789,请改用:
代码语言:javascript复制/var/www/html/.htaccessRewriteCond %{REMOTE_ADDR} ^(12.34.56.789)$
RewriteRule (.*) - [F,L]
结论
mod_rewrite
可以有效地用于确保人类可读的URL。然而,.htaccess
文件本身比简单的模块有更多的用途,应该注意的是,可以安装许多其他Apache模块来扩展其功能。
还有其他资源详细说明了以下功能mod_rewrite
:
- Apache mod_rewrite简介
- mod_rewrite的Apache文档
- mod_rewrite备忘单
mod_rewrite
是Web应用程序安全性的关键模块,但有时可能会出现重定向循环或无处不在的模糊500 forbidden
错误。有关调试的提示.htaccess
,请参阅此StackOverflow帖子。
为了快速分析正则表达式模式,这里有一个在线调试器,可以提供正则表达式模式的即时反馈和实时解释。
更多Ubuntu教程请前往腾讯云 社区学习更多知识。
参考文献:《How To Set Up mod_rewrite for Apache on Ubuntu 14.04》