.htaccess文件使用详解与性能提升

发布于 2020-12-07  137 次阅读


因为前几天部署了SSL,然后又懒得折腾子域名,因此需要使用.htaccess文件对博客子文件夹中的一些规则进行重写。借此机会了解了一些.htaccess文件的简单语法和使用规则。文章详解部分的例子参考了这篇文章,性能优化部分参考了《Apache cookbook 第二版》。

.htaccess文件详解

.htaccess文件是什么?

.htaccess文件(或者"分布式配置文件")提供了针对目录改变配置的方法, 即,在一个特定的文档目录中放置一个配置文件, 以作用于此目录及其所有子目录。管理员可以通过Apache的AllowOverride指令来设置。

概述来说,htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。

启用.htaccess,需要修改httpd.conf启用AllowOverride,并可以用AllowOverride限制特定命令的使用。如果需要使用.htaccess以外的其他文件名,可以用AccessFileName指令来改变。例如,需要使用.config ,则可以在服务器配置文件中按以下方法配置:AccessFileName .config 。

在这里注意一下,在我所用过的SFTP软件中,.htaccess文件都是隐藏文件,因此需要设置以后才能看见。同样地,在Linux下 需要使用ls -a指令才能显示出隐藏文件。

.htaccess文件的作用范围


.htaccess文件中的配置指令作用于.htaccess文件所在的目录及其所有子目录,但是很重要的、需要注意的是,其上级目录也可能会有.htaccess文件,而指令是按查找顺序依次生效的,所以一个特定目录下的.htaccess文件中的指令可能会覆盖其上级目录中的.htaccess文件中的指令,即子目录中的指令会覆盖父目录或者主配置文件中的指令。

同时,因为 .htaccess 文件会对子目录生效,这意味着:如果在配置文件中使用AllowOverride指令启用了.htaccess文件,则Apache需要在每个目录中查找.htaccess文件。因此,无论是否真正用到,启用.htaccess都会导致性能的下降。另外,对每一个请求,都需要读取一次.htaccess文件。

同时,Apache必须在所有上级的目录中查找.htaccess文件,以使所有有效的指令都起作用(参见指令的生效),这也将极大地影响性能。

b比方说,如果请求/www/test/example中的页面,Apache必须查找以下文件:

/.htaccess  /www/.htaccess  /www/test/.htaccess  /www/test/example/.htaccess

如果你的网站文件目录错综复杂的话,这将是一个蛮大的开销。

.htaccess语法

以下面这段 .htaccess文件的内容为例:

RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www\.)?xxx\.com$
RewriteCond %{REQUEST_URI} !^/blog/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /blog/$1

# 没有输入文件名的默认到到首页
RewriteCond %{HTTP_HOST} ^(www\.)?xxx\.com$
RewriteRule ^(/)?$ blog/index.php [L]

【RewriteEngine On】
表示重写引擎开,作用就是打开URL的重写引擎。

【RewriteCond %{HTTP_HOST} ^(www\.)?xxx\.com$】
RewriteCond表示重写条件,前面%{HTTP_HOST}表示当前访问的网址,只是指前缀部分,格式是www.xxx.com不包括“http://”和“/”,^表示 字符串开始,$表示字符串结尾,\.表示转义的. ,如果不转义也行,推荐转义,防止有些服务器不支持,?表示前面括号www\.出现0次或1次,这句规则的意思就是如果访问的网址是xxx.com或者 www.xxx.com就执行以下的语句,不符合就跳过。

【RewriteCond %{REQUEST_URI} !^/blog/】
也是重写条件,%{REQUEST_URI}表示访问的相对地址,就是相对根目录的地址,就是域名/后面的成分,格式上包括最前面的“/”,!表示非,这句语句表示访问的地址不以/blog/开头,只是开头^,没有结尾$

【RewriteCond %{REQUEST_FILENAME} !-f】
【RewriteCond %{REQUEST_FILENAME} !-d】

这两句语句的意思是请求的文件或路径是不存在的,如果文件或路径存在将返回已经存在的文件或路径

【RewriteRule ^(.*)$ /blog/$1】
重写规则,最重要的部分,意思是当上面的RewriteCond条件都满足的时候,将会执行此重写规则,^(.*)$是一个正则表达的 匹配,匹配的是当前请求的URL,^(.*)$意思是匹配当前URL任意字符,.表示任意单个字符,*表示匹配0次或N次(N>0),后面 /blog/$1是重写成分,意思是将前面匹配的字符重写成/blog/$1,这个$1表示反向匹配,引用的是前面第一个圆括号的成分,即^(.*)$中 的.* ,其实这儿将会出现一个问题,后面讨论。

【RewriteCond %{HTTP_HOST} ^(www\.)?xxx\.com$】
【RewriteRule ^(/)?$ blog/index.php [L]】

这两句的意思是指请求的host地址是www.xxx.com,如果地址的结尾只有0个或者1个“/”时,将会重写到子目录下的主页,这主要因为重写后的地址是不能自动寻找主页的,需要自己指定。关于这个问题的解决办法我会在下一个帖子中回答(挖坑ing)。

但是,现在有一个问题:如果请求网址是http://www.xxx.com/a.html,到底是匹配整个http://www.xxx.com/a.html,还是只匹配/a.html即反斜杠后面的成分,还是只匹配a.html呢?
答案是:根据RewriteBase规则规定,如果rewritebase 为/,将会匹配a.html,不带前面的反斜杠,所以上条语句应该写成RewriteRule ^(.*)$ blog/$1(不带/),不过实际应用上带上前面的反斜杠,也可以用,可能带不带都行。现在问题出来了,如果不设置rewritebase 为/ ,将会匹配整个网址http://www.xxx.com/a.html,显然这是错误的,所以应该添加这条:RewiteBase /

性能提升:

事实上前面已经说了,当你在 httpd.conf 文件中启用了:

AllowOverride All

那么当你访问某个子目录时,服务器会深度地搜索路径中所有文件夹下的.htaccess文件(无论这个文件是否存在)。这会显著影响网站的性能(尤其是apache还这么笨重的情况下)。

在/www/test/example目录下的.htaccess文件中放置指令,与在主配置文件中<Directory /www/test/example>段中放置相同指令,是完全等效的。

/www/test/example目录下的.htaccess文件的内容:

AddType text/example.exm


httpd.conf文件中摘录的内容:

<Directory /www/test/example>
AddType text/example.exm
</Directory>

是完全等效的,因此在大部分情况下,我们都应该把.htaccess文件的内容写在httpd.conf中,而不是写在.htaccess文件中。并将AllowOverride设置为none以完全禁止使用.htaccess文件。

如果一定要在网站中的某个地方启用.htaccess文件,也应该指定启用的路径。

<Directory /www/test/example>
AllowOverride All
</Directory>

你好哇!欢迎来到雷公马碎碎念的地方:)