apache重写规则

Aapache重写规则

.htaccess叫分布式配置文件,.htaccess文件的作用在于当浏览器通过uri访问到服务器某个文件夹或文件时,我们可以决定这个uri是否访问uri指定资源或者拒绝访问。并且通过一个十分友好的uri吸引用户进来,并且通过.htaccess文件把用户导向服务器指定的访问位置。它提供了针对目录改变配置的方法——在一个特定的文档目录中放置一个包含一个或多个指令的文件, 以作用于此目录及其所有子目录。并且子目录中的指令会覆盖更高级目录或者主服务器配置文件中的指令。说的通俗点,他就是:一个更改服务器配置的‘文本’文件。一般来说,如果你的虚拟主机使用的是Unix或Linux系统,或者任何版本的Apache网络服务器,从理论上讲都是支持.htaccess的。他可以实现包括:文件夹密码保护、用户自动重定向、自定义错误页面、改变你的文件扩展名、封禁特定IP地址的用户、只允许特定IP地址的用户、禁止目录列表,以及使用其他文件作为index文件等等。

前提

必须开启apache里面的重写模块!

  • 第一步,首先进入apache安装目录下,找到httpd.conf配置文件,并打开httpd.conf。
# 找到下面这行代码,取消其注释符号 ‘#’。
# LoadModule reqtimeout_module libexec/apache2/mod_reqtimeout.so
  • 第二步,找到所有的AllowOverride denied并改为AllowOverride all——意思就是支持重写。

  • 第三步,重启apache服务器。

.htaccess基本语法介绍

基本语句

语句 含义
RewriteEngine on 开启apache重写功能
RewriteBase / 设置重写根目录
RewriteCond rewrite condition 重写条件,匹配符合条件——正则的请求
RewriteRule 重定向

RewriteBase

RewriteEngine on
RewriteBase /
RewriteRule ^(.*)\.htm$ $1.php [R,NC,L]

RewriteBase定义了重写基准目录。
例如,如果你将虚拟站点设置在/var/www目录下,删除这行将会导致重定向到http://yourdomain.com/var/www/1.php。显然这是找不到的,而且你也不会希望用户看见你的服务器的目录结构。
再举个例子,如果RewriteBase /base/,那么将会重定向到http://yourdomain.com/base/1.php
对于重写基准目录,我们还可以通过将$1.php变成/$1.php实现直接变换,这时就可以将RewriteBase省略。

RewriteCond说明

语法

【说明 】定义重写发生的条件
【语法】 RewriteCond 【TestString】 【CondPattern】 [flags]
【作用域】 server config, virtual host, directory, .htaccess
【覆盖项】 FileInfo
【状态】 扩展(E)
【模块】 mod_rewrite

注意事项

  1. 可以在CondPattern串的开头使用’!'(惊叹号)来指定不匹配。

  2. CondPatterns有若干特殊的变种。除了正则表达式的标准用法,还有下列用法:

    ‘<CondPattern’(词典顺序的小于)
    将CondPattern视为纯字符串,与TestString按词典顺序进行比较。如果TestString小于CondPattern则为真。
    ‘>CondPattern’(词典顺序的大于)
    将CondPattern视为纯字符串,与TestString按词典顺序进行比较。如果TestString大于CondPattern则为真。
    ‘=CondPattern’(词典顺序的等于)
    将CondPattern视为纯字符串,与TestString按词典顺序进行比较。如果TestString等于CondPattern(两个字符串逐个字符地完全相等)则为真。如果CondPattern是”"(两个双引号),则TestString将与空字符串进行比较。
    ‘-d’(目录)
    将TestString视为一个路径名并测试它是否为一个存在的目录。
    ‘-f’(常规文件)
    将TestString视为一个路径名并测试它是否为一个存在的常规文件。
    ‘-s’(非空的常规文件)
    将TestString视为一个路径名并测试它是否为一个存在的、尺寸大于0的常规文件。
    ‘-l’(符号连接)
    将TestString视为一个路径名并测试它是否为一个存在的符号连接。
    ‘-x’(可执行)
    将TestString视为一个路径名并测试它是否为一个存在的、具有可执行权限的文件。该权限由操作系统检测。
    ‘-F’(对子请求存在的文件)
    检查TestString是否为一个有效的文件,而且可以在服务器当前的访问控制配置下被访问。它使用一个内部子请求来做检查,由于会降低服务器的性能,所以请谨慎使用!
    ‘-U’(对子请求存在的URL)
    检查TestString是否为一个有效的URL,而且可以在服务器当前的访问控制配置下被访问。它使用一个内部子请求来做检查,由于会降低服务器的性能,所以请谨慎使用!
    
  3. 还可以在CondPattern之后追加特殊的标记[flags]作为RewriteCond指令的第三个参数。flags是一个以逗号分隔的以下标记的列表:

    • ‘nocase|NC’(忽略大小写)

      它使测试忽略大小写,扩展后的TestString和CondPattern中’A-Z’ 和’a-z’是没有区别的。此标记仅用于TestString和CondPattern的比较,而对文件系统和子请求的检查不起作用。

    • ‘ornext|OR’(或下一条件)

      它以OR方式组合若干规则的条件,而不是隐含的AND。

    RewriteCond %{REMOTE_HOST} ^host1.* [OR]
    RewriteCond %{REMOTE_HOST} ^host2.* [OR]
    RewriteCond %{REMOTE_HOST} ^host3.*
    RewriteRule … 针对这3个主机的规则集 …如果不用这个标记,你就必须要书写三次条件/规则对。
    

RewriteRule配置参数

语句 含义
R 强制外部重定向;R=301 永久重定向、R=302 临时重定向
F 禁止URL,返回403 http状态码
G 强制URL为GONE,返回410 http状态码
P 强制使用代理转发
L 表明当前规则是最后一条规则,停止分析以后的规则重写
N 重新从第一条规则开始运行重写过程
C 与下一条规则关联
T=MIME-type(force MIME type) 强制MIME类型
NS 只是用于不是内部的子请求
NC 不区分大小写
QSA 追加请求字符串
NE 不再输出转义特殊字符 %3d$1 等价于 =$1

生效条件

【说明 】定义重写发生的条件
【语法】 RewriteCond 【TestString】 【CondPattern】 [flags]
【作用域】 server config, virtual host, directory, .htaccess
【覆盖项】 FileInfo
【状态】 扩展(E)
【模块】 mod_rewrite

RewriteCond指令定义了规则生效的条件,即在一个RewriteRule指令之前可以有一个或多个RewriteCond指令。条件之后的重写规则仅在当前URIPattern匹配并且满足此处的条件(TestString能够与CondPattern匹配)时才会起作用。

  1. RewriteRule反向引用 ,引用方法是:$N (0 <= N <= 9)引用当前(带有若干RewriteRule指令的)RewriteCond中的与Pattern匹配的分组成分(圆括号!)。
  2. RewriteCond反向引用 ,引用方法是:%N (1 <= N <= 9)引用当前若干RewriteCond条件中最后符合的条件中的分组成分(圆括号!)。
  3. RewriteMap扩展 ,引用方法是:${mapname:key|default} 细节请参见RewriteMap 指令。
  4. 服务器变量 ,引用方法是:%{NAME_OF_VARIABLE} NAME_OF_VARIABLE可以是下节apache环境变量列出的字符串之一:

apache环境变量

获取环境变量

在上一节中讲述了 %{} 代表获取环境变量;可以获取的环境变量中的任何变量。具体内容还需要参见官方文档中——重写模块,要分析环境变量最好的方法phpinfo();访问地址写全一点http://www.fuermao.com/index.php?1111#111,环境变量的类型如下表(phpinfo()所获取的并不是特别全):

apache环境变量

HTTP Header Information

官方其他参数说明

IS_SUBREQ
如果正在处理的请求是一个子请求,它将包含字符串”true”,否则就是”false”。模块为了解析URI中的附加文件,可能会产生子请求。
API_VERSION
这是正在使用中的Apache模块API(服务器和模块之间内部接口)的版本, 其定义位于include/ap_mmn.h中。此模块API版本对应于正在使用的Apache的版本(比如在Apache 1.3.14的发行版中这个值是19990320:10)。 通常,对它感兴趣的是模块的开发者。
THE_REQUEST
这是由浏览器发送的完整的HTTP请求行(比如:”GET /index.html HTTP/1.1″)。它不包含任何浏览器发送的其它头信息。
REQUEST_URI
这是在HTTP请求行中所请求的资源(比如上述例子中的”/index.html”)。
REQUEST_FILENAME
这是与请求相匹配的完整的本地文件系统的文件路径名。
HTTPS
如果连接使用了SSL/TLS,它将包含字符串”on”,否则就是”off”(无论mod_ssl是否已经加载,该变量都可以安全的使用)。

注意事项

  1. SCRIPT_FILENAME和REQUEST_FILENAME包含的值是相同的——即Apache服务器内部的request_rec结构中的filename字段。 第一个就是大家都知道的CGI变量名,而第二个则是REQUEST_URI(request_rec结构中的uri字段)的一个副本。

  2. 特殊形式:%{ENV:variable} ,其中的variable可以是任意环境变量。它是通过查找Apache内部结构或者(如果没找到的话)由Apache服务器进程通过getenv()得到的。

  3. 特殊形式:%{SSL:variable} ,其中的variable可以是一个SSL环境变量的名字,无论mod_ssl模块是否已经加载都可以使用(未加载时为空字符串)。比如:%{SSL:SSL_CIPHER_USEKEYSIZE}将会被替换为128。

  4. 特殊形式:%{HTTP:header} ,其中的header可以是任意HTTP MIME头的名称。它总是可以通过查找HTTP请求而得到。比如:%{HTTP:Proxy-Connection}将被替换为Proxy-Connection:HTTP头的值。

  5. 预设形式:%{LA-U:variable} ,variable的最终值在执行一个内部(基于URL的)子请求后确定。 当需要使用一个目前未知但是会在之后的过程中设置的变量的时候,就可以使用这个方法。例如,需要在服务器级配置(httpd.conf文件)中根据REMOTE_USER变量进行重写, 就必须使用%{LA-U:REMOTE_USER}。因为此变量是由URL重写(mod_rewrite)步骤之后的认证步骤设置的。 但是另一方面,因为mod_rewrite是通过API修正步骤来实现目录级(.htaccess文件)配置的, 而认证步骤先于API修正步骤,所以可以用%{REMOTE_USER}。

  6. 预设形式:%{LA-F:variable} ,variable的最终值在执行一个内部(基于文件名的)子请求后确定。 大多数情况下和上述的LA-U是相同的。

CondPattern是条件模式,即一个应用于当前TestString实例的正则表达式。TestString将被首先计算,然后再与CondPattern匹配。

调试重写模块

关于调试信息

关于调试这部分由于不能够直接打印和输出,所以需要在apache的日志中去查找相关信息。apache的日志大致分为两类,如:

  • access_log:访问或请求apache服务日志的访问信息;
  • error_log:apache服务器出错时的,日志记录错误信息;

日志一般都在httpd.conf文件的相关位置有路径,当然可以改变日志记录的路径;

# 错误日志
# ErrorLog: The location of the error log file.
# If you do not specify an ErrorLog directive within a <VirtualHost>
# container, error messages relating to that virtual host will be
# logged here.  If you *do* define an error logfile for a <VirtualHost>
# container, that host's errors will be logged there and not here.
# 这个地方时我修改后的错误日志记录信息位置
ErrorLog "/Users/futianyu/log/apache/error_log"

# 这个地方是日志记录级别:一共有8个级别;
# LogLevel: Control the number of messages logged to the error_log.
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
#
# 暂时注释掉
# LogLevel warn
# 重写调试时打开,因为要调试重写模块
LogLevel info rewrite:trace5

#
# The location and format of the access logfile (Common Logfile Format).
# If you do not define any access logfiles within a <VirtualHost>
# container, they will be logged here.  Contrariwise, if you *do*
# define per-<VirtualHost> access logfiles, transactions will be
# logged therein and *not* in this file.
# 这个地方就是访问日志,当然我也改了路径了;
CustomLog "/Users/futianyu/log/apache/access_log" common

设置日志输出级别

此处我们需要查看的是重写模块调试时的错误信息,给个官方文档的连接;重写模块日志记录中的Per-module logging部分有说明;改了写配置文件需要重启httpd服务器,不然不会生效。在上面的代码中文档已经给出了日志级别的说明:debug, info, notice, warn, error, crit,alert, emerg

示例

示例一

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

    表示重写引擎开,关闭Off,作用就是方便的开启或关闭以下的语句。

  • RewriteCond %{HTTP_HOST} \^(www\.)?xxx\.com$

    RewriteCond [匹配的字符串] [正则条件]
    %{}在上面也说明了,代表获取的系统变量;
    这条语句表示重写条件,如果【匹配字符串】符合【正则条件】,则执行后面的语句;
    这里需要指出的是,HTTP_HOST变量是会携带端口号(默认80端口是不会携带的),且无http://协议格式。
    获取的访问URL中的www.xxx.com,如果符合正则条件则,继续执行下面的语句。

  • `RewriteCond %{REQUEST_URI} !^/blog/``

    获取请求资源虚拟地址,REQUEST_URI是域名后至hash(#)前的部分,例如下面的网址:
    http://www.baidu.com/aa/bb/cc.php?dd=111#ee
    那么REQUEST_URI所获取的部分就是aa/bb/cc.php?dd=111
    回到正题上,如果获取到的虚拟地址信息不是以/blog/开头(正则前面有个!),则执行下面的条件;

  • RewriteCond %{REQUEST_FILENAME} !-fRewriteCond %{REQUEST_FILENAME} !-d

    这两条语句就一起讲了,如果请求的文件不是文件,不是目录的话,就执行下面的重写规则RewriteRule ^(/)?$ blog/index.php [L]

  • RewriteRule ^(.*)$ /blog/$1

    这条语句是整个重写的终点也是难点部分,意思是当上面的RewriteCond条件都满足的时候,将会执行此重写规则;^(.*)$ 匹配的是当前请求URL地址,整个地址都匹配,所以是.*代表表示任意单个字符,*表示匹配0次或N次(N>0);后面的/blog/$1 就是重写部分,意思是将前面匹配的字符重写成/blog/$1。这个$1表示反向匹配,引用的是前面第一个圆括号的成分,即^(.*)$中 的.*。这里出现一个问题。
    【注意】
    如果请求地址是:http://www.xxx.com/a.html,到底是匹配整个http://www.xxx.com/a.html,还是只匹配/a.html即反斜杠后面的成分,还是只匹配a.html

    根据RewriteBase规则规定,如果Rewritebase 为/,将会匹配a.html,不带前面的反斜杠,所以上条语句应该写成RewriteRule ^(.*)$ blog/$1(不带/)而不是/blog/$1。现在问题出来了,如果不设置Rewritebase/ ,将会匹配整个网址http://www.xxx.com/a.html,显然这是错误的,所以应该添加这条:RewiteBase /

第二部分 重写规则

  • RewriteCond %{HTTP_HOST} ^(www\.)?xxx\.com$

  • RewriteRule ^(/)?$ blog/index.php [L]

    这两句的意思是指请求的host地址是www.xxx.com,如果地址的结尾只有0个或者1个“/”时,将会重写到子目录下的主页,主要因为重写后的地址是不能自动寻找主页的,需要自己指定。

正确答案
RewriteEngine On
RewiteBase /
RewriteCond %{HTTP_HOST} ^(www\.)?xxx\.com$ [NC]
RewriteCond %{REQUEST_URI} !^/blog/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ blog/$1

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

示例二 将.htm页面映射到.php

Options +FollowSymlinks
RewriteEngine on
RewriteRule ^(.*)\.htm$ $1.php [NC]

注意事项:

  • 该RewriteRule能够将.htm静态页面映射到.php动态页面
  • 如果通过.htm进入,浏览器地址栏显示的是.htm扩展名,但服务器上实际执行的是.php
  • 必须保证服务器上有对应的.php,否则会404
  • 浏览器和搜索引擎可以同时通过.htm和.php访问网页
  • 如果该目录上存在.htm,将被忽略
  • [NC]表示“不区分大小写”,更多类似定义请参考本站《.htaccess正则表达式》一文

示例三 长短地址转换

若访问http://mysite/grab?file=my.zip
如何实际访问至http://mysite/public/files/download/download.php?file=my.zip

RewriteEngine On
RewriteRule ^grab /public/files/download/download.php

示例四 支持多域名访问

现在假设你有域名domain-one.com和domain-two.com,并且在服务器根目录有对应文件夹one和two,那么通过下面的改写就能让Apache同时接受者两个域名的请求:

RewriteCond %{HTTP_HOST} domain-one.com
RewriteCond %{REQUEST_URI} !^/one
RewriteRule ^(.*)$ /one/$1 [L]

RewriteCond %{HTTP_HOST} domain-two.com
RewriteCond %{REQUEST_URI} !^/two
RewriteRule ^(.*)$ /two/$1 [L]

示例五 去掉www

Options +FollowSymlinks
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.(.*) [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,NC,L]

示例六 加上www

RewriteEngine On
RewriteCond %{HTTP_HOST} ^(.*)$
RewriteRule (.*) http://www\.%1/$1 [R=301,L]

参考资料

《.htaccess 基础教程(四)Apache RewriteCond 规则参数》 http://www.cnblogs.com/52php/p/5670199.html

《 .htaccess技巧: URL重写(Rewrite)与重定向(Redirect)》 https://blog.csdn.net/newjueqi/article/details/12014673 维摩诘

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容

  • 看了一些关于.htaccess,apache重写url的规则,一般都写得很清楚。但是对于我一个小白,感觉要挖的东西...
    yancolin阅读 5,490评论 0 3
  • 1、简介 Apached的重写功能,即是mod_rewrite模块功能,它是apache的一个模块。它的功能非常强...
    呦丶耍脾气阅读 528评论 0 0
  • 重写规则 【重写规则的作用范围】 可以使用在Apache主配置文件httpd.conf中 可以使用在httpd.c...
    桖辶殇阅读 1,652评论 0 0
  • 前两天部署一个项目到本机环境,从nginx转到apache,因为不熟悉apache的重写规则,给自己挖了很多坑。。...
    牵小马过河阅读 1,033评论 0 0
  • 作者:烨竹 简单理解 URL重写就是首先获得一个进入的URL请求然后把它重新写成网站可以处理的另一个URL的过程 ...
    DragonRat阅读 4,423评论 0 0