您现在的位置是:首页> 操作系统> Linux> apache

apache的Rewrite详解

  • 3176人已阅读
  • 时间:2018-10-16 09:05:32
  • 分类:apache
  • 作者:祥哥

一、Rewrite标志说明
    R[=code](force redirect) 强制外部重定向
    G(force URL to be gone) 强制URL为GONE,返回410HTTP状态码。
    P(force proxy) 强制使用代理转发。
    L(last rule) 表明当前规则是最后一条规则,停止分析以后规则的重写。
    N(next round) 重新从第一条规则开始运行重写过程。
    C(chained with next rule) 与下一条规则关联
    如果规则匹配则正常处理,该标志无效,如果不匹配,那么下面所有关联的规则都跳过
    T=MIME-type(force MIME type) 强制MIME类型
    NS (used only if no internal sub-request) 只用于不是内部子请求
    NC(no case) 不区分大小写
    QSA(query string append) 追加请求字符串
    NE(no URI escaping of output) 不在输出转义特殊字符
    例如:
    RewriteRule /foo/(.*) /bar?arg=P1\%3d$1 [R,NE] 将能正确的将/foo/zoo转换成/bar?arg=P1=zed
    PT(pass through to next handler) 传递给下一个处理
    例如:
    RewriteRule ^/abc(.*) /def$1 [PT] # 将会交给/def规则处理
    Alias /def /ghi
    S=num(skip next rule(s)) 跳过num条规则
    E=VAR:VAL(set environment variable) 设置环境变量
二、RewiriteCond标志
    'nocase|NC'(no case)忽略大小
    'ornext|OR' (or next condition)逻辑或,可以同时匹配多个RewriteCond条件RewriteRule适用的标志符
    'redirect|R [=code]' (force redirect)强迫重写为基于http开头的外部转向(注意URL的变化) 如:[R=301,L]
    'forbidden|F' (force URL to be forbidden)重写为禁止访问
    'proxy|P' (force proxy)重写为通过代理访问的http路径
    'last|L' (last rule)最后的重写规则标志,如果匹配,不再执行以后的规则
    'next|N' (next round)循环同一个规则,直到不能满足匹配
    'chain|C' (chained with next rule)如果匹配该规则,则继续下面的有Chain标志的规则。
    'type|T=MIME-type' (force MIME type)指定MIME类型
    'nosubreq|NS' (used only if no internal sub-request)如果是内部子请求则跳过
    'nocase|NC' (no case)忽略大小
    'qsappend|QSA' (query string append)附加查询字符串
    'noescape|NE' (no URI escaping of output)禁止URL中的字符自动转义成%[0-9]+的形式。
    'passthrough|PT' (pass through to next handler)将重写结果运用于mod_alias
    'skip|S=num' (skip next rule(s))跳过下面几个规则
    'env|E=VAR:VAL' (set environment variable)添加环境变量
三、Rewrite规则表达式的说明
    . 匹配任何单字符
    [chars] 匹配字符串:chars
    [^chars] 不匹配字符串:chars
    text1|text2 可选择的字符串:text1或text2
    ? 匹配0到1个字符
    * 匹配0到多个字符
    + 匹配1到多个字符
    ^ 字符串开始标志
    $ 字符串结束标志
    \n 转义符标志
    反向引用 $N 用于 RewriteRule 中匹配的变量调用(0 <= N <= 9)
    反向引用 %N 用于 RewriteCond 中最后一个匹配的变量调用(1 <= N <= 9)
四、Rewrite服务器变量
    Apache提供给rewirte模块的环境变量大概分成5个类型.
    第一部分: HTTP headers 部分参数
    参数名称: HTTP_USER_AGENT
    样例参考值: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.0.8) Gecko/2009032609 Firefox/3.0.8
    说明: 相当于PHP中的服务器参数: $_SERVER["HTTP_USER_AGENT"]
    参数名称: HTTP_REFERER
    样例参考值: http://www.test.cn/test.php
    说明: 相当于PHP中的服务器参数: _SERVER["HTTP_REFERER"]
    参数名称: HTTP_COOKIE
    样例参考值: ZDEDebuggerPresent=php,phtml,php3
    说明: 相当于PHP中的服务器参数: $_SERVER["HTTP_COOKIE"]
    参数名称: HTTP_FORWARDED
    样例参考值: 如果使用代理服务器的话会是代理服务器的IP地址, 本地不容易搭环境测试出值来.
    说明: 相当于PHP中的服务器参数: $_SERVER["HTTP_FORWARDED"]
    参数名称: HTTP_HOST
    样例参考值: www.test.com
    说明: 相当于PHP中的服务器参数: $_SERVER["HTTP_HOST"]
    参数名称: HTTP_PROXY_CONNECTION
    样例参考值: 网络连接代理方面的信息. 和HTTP_FORWARDED参数一样. 本地不容易搭环境测试出值来.
    说明: PHP中貌似未提供这样的服务器信息值. 如果又的话可能等值于: $_SERVER["HTTP_PROXY_CONNECTION"]
    参数名称: HTTP_ACCEPT
    样例参考值: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    说明: 相当于PHP中的服务器参数: $_SERVER["HTTP_ACCEPT"]
    第二部分: server internals 部分参数
    参数名称: DOCUMENT_ROOT
    样例参考值: C:/webRoot/t
    说明: 相当于PHP中的服务器参数: $_SERVER["DOCUMENT_ROOT"]
    参数名称: SERVER_ADMIN
    样例参考值: youemailaddress@gmail.com
    说明: 相当于PHP中的服务器参数: $_SERVER["SERVER_ADMIN"]
    参数名称: SERVER_NAME
    样例参考值: www.test.com
    说明: 相当于PHP中的服务器参数: $_SERVER["SERVER_NAME"]
    参数名称: SERVER_ADDR
    样例参考值: 127.0.0.1
    说明: 相当于PHP中的服务器参数: $_SERVER["SERVER_ADDR"]
    参数名称: SERVER_PORT
    样例参考值: 80
    说明: 相当于PHP中的服务器参数: $_SERVER["SERVER_PORT"]
    参数名称: SERVER_PROTOCOL
    样例参考值: HTTP/1.1
    说明: 相当于PHP中的服务器参数: $_SERVER["SERVER_PROTOCOL"]
    参数名称: SERVER_SOFTWARE
    样例参考值: Apache/2.2.11 (Win32) PHP/5.2.9-1
    说明: 相当于PHP中的服务器参数: $_SERVER["SERVER_SOFTWARE"]
    第三部分: connection & request 部分参数
    参数名称: REMOTE_ADDR
    样例参考值: 127.0.0.1 正在浏览当前页面用户的 IP 地址。
    说明: 相当于PHP中的服务器参数: $_SERVER["REMOTE_ADDR"]
    参数名称: REMOTE_HOST
    样例参考值: 127.0.0.1 正在浏览当前页面用户的主机名。反向域名解析基于该用户的 REMOTE_ADDR
    说明: 相当于PHP中的服务器参数: $_SERVER["REMOTE_HOST"]
    参数名称: REMOTE_PORT
    样例参考值: 2574 (变化的值)用户连接到服务器时所使用的端口
    说明: 相当于PHP中的服务器参数: $_SERVER["REMOTE_PORT"]
    参数名称: REMOTE_USER
    样例参考值: 空
    说明: PHP 好像未提供相关的$_SERVER值.
    参数名称: REMOTE_IDENT
    样例参考值: 空
    说明: PHP 好像未提供相关的$_SERVER值.
    参数名称: REQUEST_METHOD
    样例参考值: GET
    说明: 相当于PHP中的服务器参数: $_SERVER["REQUEST_METHOD"]
    参数名称: SCRIPT_FILENAME
    样例参考值: C:/webRoot/t/share77.html
    说明: 相当于PHP中的服务器参数: $_SERVER["SCRIPT_FILENAME"]
    参数名称: PATH_INFO
    样例参考值: 空
    说明: 相当于PHP中的服务器参数: $_REQUEST["PATH_INFO"]
    参数名称: QUERY_STRING
    样例参考值: a=b&c=d&e=f
    说明: 相当于PHP中的服务器参数: $_SERVER["QUERY_STRING"]
    参数名称: AUTH_TYPE
    样例参考值: 空 当 PHP 运行在 Apache 模块方式下,并且正在使用 HTTP 认证功能,这个是认证的类型
    说明: 相当于PHP中的服务器参数: $_SERVER["AUTH_TYPE"]
    第四部分: date and time 部分参数
    参数名称: TIME_YEAR
    样例参考值: 2009
    说明: 服务器获取当前的年份值
    参数名称: TIME_MON
    样例参考值: 04
    说明: 服务器获取当前的月份值
    参数名称: TIME_DAY
    样例参考值: 22
    说明: 服务器获取当前的日值
    参数名称: TIME_HOUR
    样例参考值: 16
    说明: 服务器获取当前时间的小时
    参数名称: TIME_MIN
    样例参考值: 26
    说明: 服务器获取当前时间的分钟
    参数名称: TIME_SEC
    样例参考值: 34
    说明: 服务器获取当前时间的秒
    参数名称: TIME_WDAY
    样例参考值: 3
    说明: 服务器获取当天是星期几, 从星期日-星期六, 数字从 0-6
    参数名称: TIME
    样例参考值: 20090422162634
    说明: 服务器获取当前的时间, 格式为: 年月日时分秒
    第四部分: specials 部分参数
    参数名称: API_VERSION
    样例参考值: 20051115:21
    说明: apache 的 API 版本信息.
    参数名称: THE_REQUEST
    样例参考值: GET /share77.html HTTP/1.1
    说明: 浏览器发给服务器的请求值. 不包括其他的头信息.
    参数名称: REQUEST_URI
    样例参考值: /share77.html
    说明: 浏览器请求的资源信息.
    参数名称: REQUEST_FILENAME
    样例参考值: C:/webRoot/t/share77.html
    说明: 被请求的资源的在磁盘的物理地址.
    参数名称: IS_SUBREQ
    样例参考值: false
    说明: 如果是 sub-request 则显示为 true, 否则为 false.
    参数名称: HTTPS
    样例参考值: off
    说明: 如果连接使用 SSL/TLS 模式, 则值为on , 否则值为off, 这个参数比较安全, 即使未载入 mod_ssl 模块时
    注意:一定不要忘记,在服务器范围内的配置文件中,模板(pattern)用以匹配整个URL;而在目录范围内的配置文件中,目录前缀总是 被自动去掉后再进行模板匹配的,且在替换完成后自动再加上这个前缀。这个功能对很多种类的重写是非常重要的,因为如果没有去前缀,则要进行父目录的匹配, 而父目录的信息并不是总能得到的。一个例外是,当substitution中有http://打头时,则不再自动增加前缀了,如果P标志出现,则会强制转 向代理。
    注意:如果要在某个目录范围内启动重写引擎,则需要在相应的目录配置文件中设置“RewriteEngine on”,且目录的“Options FollowSymLinks”必须设置。如果管理员由于安全原因没有打开FollowSymLinks,则不能使用重写引擎。
五、RewriteCond指令格式
    语法: RewriteCond TestString CondPattern [flags]
    RewriteCond指令定义一条规则条件。在一条RewriteRule指令前面可能会有一条或多条RewriteCond指令,只有当自身的模板(pattern)匹配成功且这些条件也满足时规则才被应用于当前URL处理。
    1、 TestString是一个纯文本的字符串,除了包含普通的字符外,还可以包括下列的可扩展结构:
    1)$N:RewriteRule后向引用,其中(0 <= N <= 9) 。$N引用紧跟在RewriteCond后面的RewriteRule中模板中的括号中的模板在当前URL中匹配的数据。
    2)%N:RewriteCond后向引用,其中(0 <= N <= 9) 。%N引用最后一个RewriteCond的模板中的括号中的模板在当前URL中匹配的数据。
    3)${mapname:key|default}:RewriteMap扩展。
    2、CondPattern是条件pattern, 即一个应用于当前实例TestString的正则表达式, 即TestString将会被计算然后与CondPattern匹配。作为一个标准的扩展正则式,CondPattern有以下补充:
    1)可以在模板串前增加一个!前缀,以用表示不匹配模板。但并不是所有的test都可以加!前缀。
    2)CondPattern中可以使用以下特殊变量:
    '>CondPattern’ (大于) 将condPattern当作一个普通字符串,将它和TestString进行比较,当TestString 的字符大于CondPattern为真。
    ‘=CondPattern’ (等于) 将condPattern当作一个普通字符串,将它和TestString进行比较,当TestString 与CondPattern完全相同时为真.如果CondPattern只是 “” (两个引号紧挨在一起) 此时需TestString 为空字符串方为真。
    ‘-d’ (是否为目录) 将testString当作一个目录名,检查它是否存在以及是否是一个目录。
    ‘-f’ (是否是regular file) 将testString当作一个文件名,检查它是否存在以及是否是一个regular文件。
    ‘-s’ (是否为长度不为0的regular文件) 将testString当作一个文件名,检查它是否存在以及是否是一个长度大于0的regular文件。
    ‘-l’ (是否为symbolic link) 将testString当作一个文件名,检查它是否存在以及是否是一个 symbolic link。
    ‘-F’ (通过subrequest来检查某文件是否可访问) 检查TestString是否是一个合法的文件,而且通过服务器范围内的当前设置的访问控制进行访问。这个检查是通过一个内部subrequest完成的, 因此需要小心使用这个功能以降低服务器的性能。
    ‘-U’ (通过subrequest来检查某个URL是否存在) 检查TestString是否是一个合法的URL,而且通过服务器范围内的当前设置的访问控制进行访问。这个检查是通过一个内部subrequest完成的, 因此需要小心使用这个功能以降低服务器的性能。
    3、[flags]是第三个参数,多个标志之间用逗号分隔。
    1)’nocase|NC’ (不区分大小写)   在扩展后的TestString和CondPattern中,比较时不区分文本的大小写。注意,这个标志对文件系统和subrequest检查没有影响.
    2)’ornext|OR’ (建立与下一个条件的或的关系)   默认的情况下,二个条件之间是AND的关系,用这个标志将关系改为OR。例如: RewriteCond %{REMOTE_HOST} ^host1.* [OR] RewriteCond %{REMOTE_HOST} ^host2.* [OR] RewriteCond %{REMOTE_HOST} ^host3.* RewriteRule … 如果没有[OR]标志,需要写三个条件/规则.
六、RewriteRule 指令
    语法: RewriteRule Pattern Substitution [flags]
    1) Pattern是一个作用于当前URL的兼容perl的正则表达式. 这里的“当前”是指该规则生效时的URL的值。
    2) Substitution是,当原始URL与Pattern相匹配时,用以替代(或替换)的字符串。
    3) 此外,Substitution还可以追加特殊标记[flags] 作为RewriteRule指令的第三个参数。 Flags是一个包含以逗号分隔的下列标记的列表:
    redirect|R [=code] (强制重定向 redirect)
    以 http://thishost[:thisport]/(使新的URL成为一个URI) 为前缀的Substitution可以强制性执行一个外部重定向。 如果code没有指定,则产生一个HTTP响应代码302(临时性移动)。如果需要使用在300-400范围内的其他响应代码,只需在此指定这个数值即可, 另外,还可以使用下列符号名称之一: temp (默认的), permanent, seeother. 用它可以把规范化的URL反馈给客户端,如, 重写“/~”为 “/u/”,或对/u/user加上斜杠,等等。
    注意: 在使用这个标记时,必须确保该替换字段是一个有效的URL! 否则,它会指向一个无效的位置! 并且要记住,此标记本身只是对URL加上 http://thishost[:thisport]/的前缀,重写操作仍然会继续。通常,你会希望停止重写操作而立即重定向,则还需要使用’L’标记.
    forbidden|F (强制URL为被禁止的 forbidden)
    强制当前URL为被禁止的,即,立即反馈一个HTTP响应代码403(被禁止的)。使用这个标记,可以链接若干RewriteConds以有条件地阻塞某些URL。
    gone|G’(强制URL为已废弃的 gone)
    强制当前URL为已废弃的,即,立即反馈一个HTTP响应代码410(已废弃的)。使用这个标记,可以标明页面已经被废弃而不存在了.
    proxy|P (强制为代理 proxy)
    此标记使替换成分被内部地强制为代理请求,并立即(即, 重写规则处理立即中断)把处理移交给代理模块。你必须确保此替换串是一个有效的(比如常见的以 http://hostname开头的)能够为Apache代理模块所处理的URI。使用这个标记,可以把某些远程成分映射到本地服务器名称空间, 从而增强了ProxyPass指令的功能。
    注意: 要使用这个功能,代理模块必须编译在Apache服务器中。 如果你不能确定,可以检查“httpd -l”的输出中是否有mod_proxy.c。 如果有,则mod_rewrite可以使用这个功能;如果没有,则必须启用mod_proxy并重新编译“httpd”程序。
    last|L (最后一个规则 last)
    立即停止重写操作,并不再应用其他重写规则。 它对应于Perl中的last命令或C语言中的break命令。这个标记可以阻止当前已被重写的URL为其后继的规则所重写。 举例,使用它可以重写根路径的URL(’/’)为实际存在的URL, 比如, ‘/e/www/’.
    next|N (重新执行 next round)
    重新执行重写操作(从第一个规则重新开始). 这时再次进行处理的URL已经不是原始的URL了,而是经最后一个重写规则处理的URL。它对应于Perl中的next命令或C语言中的continue命令。 此标记可以重新开始重写操作,即, 立即回到循环的头部。
    但是要小心,不要制造死循环!
    chain|C (与下一个规则相链接 chained)
    此标记使当前规则与下一个(其本身又可以与其后继规则相链接的, 并可以如此反复的)规则相链接。 它产生这样一个效果: 如果一个规则被匹配,通常会继续处理其后继规则, 即,这个标记不起作用;如果规则不能被匹配,则其后继的链接的规则会被忽略。比如,在执行一个外部重定向时, 对一个目录级规则集,你可能需要删除“.www” (此处不应该出现“.www”的)。
    type|T=MIME-type(强制MIME类型 type)
    强制目标文件的MIME类型为MIME-type。 比如,它可以用于模拟mod_alias中的ScriptAlias指令,以内部地强制被映射目录中的所有文件的MIME类型为“application/x-httpd-cgi”。
    nosubreq|NS (仅用于不对内部子请求进行处理 no internal sub-request)
    在当前请求是一个内部子请求时,此标记强制重写引擎跳过该重写规则。比如,在mod_include试图搜索可能的目录默认文件(index.xxx)时, Apache会内部地产生子请求。对子请求,它不一定有用的,而且如果整个规则集都起作用,它甚至可能会引发错误。所以,可以用这个标记来排除某些规则。
    根据你的需要遵循以下原则: 如果你使用了有CGI脚本的URL前缀,以强制它们由CGI脚本处理,而对子请求处理的出错率(或者开销)很高,在这种情况下,可以使用这个标记。
    nocase|NC (忽略大小写 no case)
    它使Pattern忽略大小写,即, 在Pattern与当前URL匹配时,’A-Z’ 和’a-z’没有区别。
    qsappend|QSA (追加请求串 query string append)
    此标记强制重写引擎在已有的替换串中追加一个请求串,而不是简单的替换。如果需要通过重写规则在请求串中增加信息,就可以使用这个标记。
    noescape|NE (在输出中不对URI作转义 no URI escaping)
    此标记阻止mod_rewrite对重写结果应用常规的URI转义规则。 一般情况下,特殊字符(如’%’, ‘$’, ‘;’等)会被转义为等值的十六进制编码。 此标记可以阻止这样的转义,以允许百分号等符号出现在输出中,如:
    RewriteRule /foo/(.*) /bar?arg=P1\=$1 [R,NE] 可以使’/foo/zed’转向到一个安全的请求’/bar?arg=P1=zed’.
    passthrough|PT (移交给下一个处理器 pass through)
    此标记强制重写引擎将内部结构request_rec中的uri字段设置为 filename字段的值,它只是一个小修改,使之能对来自其他URI到文件名翻译器的 Alias,ScriptAlias, Redirect 等指令的输出进行后续处理。举一个能说明其含义的例子:如果要通过mod_rewrite的重写引擎重写/abc为/def,然后通过mod_alias使/def转变为/ghi,可以这样:
    RewriteRule ^/abc(.*) /def$1 [PT]
    Alias /def /ghi
    如果省略了PT标记,虽然mod_rewrite运作正常, 即, 作为一个使用API的URI到文件名翻译器,它可以重写uri=/abc/…为filename=/def/…,但是,后续的mod_alias在试图作URI到文件名的翻译时,则会失效。
    注意: 如果需要混合使用不同的包含URI到文件名翻译器的模块时, 就必须使用这个标记。。混合使用mod_alias和mod_rewrite就是个典型的例子。
    For Apache hackers
    如果当前Apache API除了URI到文件名hook之外,还有一个文件名到文件名的hook, 就不需要这个标记了! 但是,如果没有这样一个hook,则此标记是唯一的解决方案。 Apache Group讨论过这个问题,并在Apache 2.0 版本中会增加这样一个hook。
    skip|S=num (跳过后继的规则 skip)
    此标记强制重写引擎跳过当前匹配规则后继的num个规则。 它可以实现一个伪if-then-else的构造: 最后一个规则是then从句,而被跳过的skip=N个规则是else从句. (它和’chain|C’标记是不同的!)
    env|E=VAR:VAL (设置环境变量 environment variable)
    此标记使环境变量VAR的值为VAL, VAL可以包含可扩展的反向引用的正则表达式$N和%N。 此标记可以多次使用以设置多个变量。这些变量可以在其后许多情况下被间接引用,但通常是在XSSI (via ) or CGI (如 $ENV{’VAR’})中, 也可以在后继的RewriteCond指令的pattern中通过%{ENV:VAR}作引用。使用它可以从URL中剥离并记住一些信息。
    cookie|CO=NAME:VAL:domain[:lifetime[:path]] (设置cookie)
    它在客户端浏览器上设置一个cookie。 cookie的名称是NAME,其值是VAL。 domain字段是该cookie的域,比如’.apache.org’, 可选的lifetime是cookie生命期的分钟数,可选的path是cookie的路径。
七、实例详解
    .htaccess中的apache rewrite写法:
    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$】
    这是重写条件,前面%{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个“/”时,将会重写到子目录下的主页,我猜想这主要因为重写后的地址是不能自动寻找主页的,需要自己指定。
    现在说说出现的问题,RewriteRule ^(.*)$ /blog/$1前部分^(.*)$将会匹配当前请求的url,例如:请求网址是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,显然这是错误的,所以应该添加这条:
    RewriteBase /
    还有一个问题是,不能保证每个人输入的网址都是小写的,如果输入大写的呢,linux系统是区分大小写的,所以应该在RewriteCond后添加[NC]忽略大小写的。
    至此,完整的语句应该是:

    RewriteEngine On
    RewriteBase /
    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]

    如果后面还继续有语句的,就不应该加上最后的[L],因为这是表示最后一条语句的意思

    防盗链的语句,同样需要添加RewiteBase /,如下:

    RewriteEngine on
    RewiteBase /
    RewriteCond %{HTTP_REFERER} !^$ [NC]
    RewriteCond %{HTTP_REFERER} !xxx.info [NC]
    RewriteRule \.(jpg|gif|png|bmp|swf|jpeg)$ /error/daolian.gif [R,NC,L]

    如果后面还继续有语句的,就不应该加上最后的[L],/error/daolian.gif为别人盗链时显示的图片。

Top