Categories
Dev

Apache的重定向和伪静态

重定向和伪静态的基本原理和方法

  1. 重定向和伪静态的实现方法:
    1. 通过.htaccess配置
      1. 工作原理: .htaccess文件提供了针对每个目录改变配置的方法。在指定目录中,放置一个.htaccess文件,此文件的作用域实用于当前目录及其所有的子目录。
      2. 性能问题: 开启页面的时候要查找所有的上级目录的.htaccess
        1. 例如:/wamp/www/project1/public 文件夹下有.htaccess文件,那么Apache会查找: /wamp/www/project1/wamp/www/wamp/ 文件夹下是否有.htaccess
        2. 建议PROD以下的环境,使用.htaccess,生产环境需要把所有的重定向文件写到Apache主配置文件中。
      3. 安全问题:允许用户自行修改服务器的配置,且在不需要重启apache的情况下生效。例如,在没有index文件的情况下,很有可能会暴露文件夹下的所有文件。
      4. 妥协: 共享服务器,访问量不够大的网站,需要更好的SEO效果的网站,可以妥协掉部分性能。
    2. 通过Apache的主配置文件字段
    3. 使用PHP等脚本文件实现(仅限外部重定向)
  2. 一个基本实例:
    1. 开启目录重定向的权限:
      AllowOverride All
      
    2. 配合 .htaccess 配合调试,不需要重启服务器。在Windows下,用CMD创建.htaccess命令:echo 1 > .htaccess
  3. RewriteEngine on 开启mod_rewrite
    1. RewriteRule ^(.*)\.htm$ $1.html 当浏览器的URL尝试访问test.htm,Apache会在此.htaccess文件的当前目录下寻找test.html文件。
  4. Apache重定向原理:
    1. https://httpd.apache.org/docs/2.4/images/rewrite_process_uri.png
    2. 防止出现死循环。

mod_rewrite 详解

1. 日志功能
  1. LogLevel Apache 2.4+
  2. RewriteLog RewriteLogLevel Apache 2.2
  3. 配置:LogLevel alert rewrite:trace8 (LogLevel 不要大于trace2,或者关闭。)
    1. 只能在Apache的主配置文件下配置,无法在.htaccess进行配置。
  4. 查看:apache_error.log 文件
2. RewriteRule语法
  1. 基本格式:RewriteRule 模式(正则匹配) 替换的URL [flags]
    1. 模式匹配,支持Perl格式的正则表达式。
    2. rewrite的预设变量和替换模式的匹配结果: $1
    3. 多个flag用逗号隔开:[R=302,C]
  2. R flag 强制外部重定向,后面可以加301和302,如果不加,则默认为302重定向。
    1. 内部重定向:浏览器的地址栏,URL不会发生变化。
    2. 外部重定向:浏览器的地址栏,URL会发生变化。
      1. 针对HTTP协议,301表示永久重定向,302表示临时重定向。
      2. 实例:RewriteRule ^/?(.*)\.html$ /src/$1.php [R=302]
      3. 搜索引擎对当前网站有SEO的评分。如果是永久重定向,那么当前网站的SEO评分,会直接给到新的重定向地址。如果是临时重定向,那么当前网站的SEO评分,不会传递到新的重定向地址,搜索引擎会对新的重定向地址,产生一个新的评分。
      4. 从SEO优化的角度来说,一般都会使用301重定向。
  3. C flag 链接下一个规则。与下一条规则形成一个整体,如果第一条规则不匹配,则下一条规则就跳过了。
    1. 实例:
      # 如果第一条规则,如果不匹配,就停止。
      RewriteRule ^/?(.*)\.htm$ /$1.html [C]
      RewriteRule ^/?(.*)\.html$ /$1.php
      
      # 如果第一条规则,如果不匹配,不对URI进行替换修改,直接进入第二条规则。
      RewriteRule ^/?(.*)\.jsp$ /$1.html
      RewriteRule ^/?(.*)\.htm$ /$1.php
      
      # 如果第一条规则,匹配,但是找不到,就对URI进行替换修改,将匹配后的结果传递给第二条,再匹配第二条规则。
      RewriteRule ^/?(.*)\.htm$ /$1.html
      RewriteRule ^/?(.*)\.html$ /$1.php
      
  4. L flag 结束规则。立即停止重写操作,并不再应用其它重写规则。当前条件匹配的时候,就不再进行重写,也不再继续进行后面规则的匹配。
    1. 实例:
      RewriteRule ^(.*) first.php [L] # 第一条匹配,对URI替换和重写,结束。
      RewriteRule ^(.*) last.php
      
      RewriteRule ^(.*) first.php # 第一条匹配,对URI替换和重写,传递给第二条规则。
      RewriteRule ^(.*) last.php # 对URI替换和重写,显示`last.php`。
      
  5. NE flag 不对URL中的特殊字符进行hexcode转码。因为匹配项,例如#?等,后面的代码可能需要使用到,于是要告诉Apache不要对URL进行转义。
    1. 实例:
      # URL 输入为 http://localhost/test.htm
      RewriteRule ^(.*)\.htm /index.php#$1 [R] 		# URL重定向为 http://localhost/index.php%23index
      RewriteRule ^(.*)\.htm /index.php#$1 [NE, R] 	# URL重定向为 http://localhost/index.php#index
      
  6. NC flag 不区分大小写。匹配规则,不区分大小写。Apache服务器是区分大小写的。
    1. 实例:
      # 
      RewriteRule ^test/(.*)\.htm /tmp/$1.htm 		#访问 /Test/1.htm 会直接寻找 Test/1.htm
      RewriteRule ^test/(.*)\.htm /tmp/$1.htm [NC]	#访问 /Test/1.htm 会继续匹配 /tmp/1.htm
      
  7. G flag 请求的网页已经失效了 Gone Apache返回服务器410
    1. 使用情况:例如下载链接,限时访问。打折码过期失效。
    2. 实例
      RewriteRule ^(.*)\.htm - [G]		#访问 /Test/1.htm 会直接寻找 Test/1.htm
      
  8. QSA flag 截取URI中的查询字符串,保留后面所有的Query String。替换并传递到下一条规则。
    1. 实例:
      # 访问URL为 http://localhost/person/1?name=test
      RewriteRule ^persons/(.*)$ /persons.php?person_id=$1 [QSA,R]  	#http://localhost/index.php?person_id=1&name=test
      RewriteRule ^persons/(.*)$ /persons.php?person_id=$1 [R]    	#http://localhost/index.php?person_id=1
      
3. RewriteBase语法
  1. RewriteBase URL-path 设置目录级别重写的基本URL。
  2. 实例
    RewriteBase /
    RewirteRule ^(.*)\.htm$ $1.html
    # 等同于
    RewriteRule ^(.*)\.htm$ /$1.html [R]
    RewriteBase /tmp
    RewirteRule ^(.*)\.htm$ $1.html
    # 等同于
    RewriteRule ^(.*)\.htm$ /tmp/$1.html [R]
    # 如果没有 / 就会使用DocumentRoot 重定向后的URL会变成 localhost\C:\wamp\www\test.html
    RewriteRule ^(.*)\.htm$ $1.html [R]
    
4. RewriteCond语法说明
  1. 基本语法:RewriteCond <testing string> <condition pattern> [flags]
    1. 指定了在RewriteRule之前的判定条件。可以有多个RewriteCond。
    2. http://httpd.apache.org/docs/2.4/images/syntax_rewritecond.png
  2. testing string 可以使用$1-$9。取的是RewriteRule的匹配结果。
    1. 实例
      # RewriteRule的条件匹配,如果没有RewriteCond就直接替换。
      # 如果有RewriteCond存在,检查当前$1是否等于“test”。如果判定结果是正确,才进行替换。
      RewriteCond $1 "test"
      RewriteRule ^(.*)\.htm $1.html
      
  3. testing string 可以使用服务器变量
    1. 例如 RewriteCond %{HTTP_HOST} "127.0.0.1"
  4. testing string 可以使用%1-%9,表示RewriteCond条件中,最后符合的条件中的组成部分。
    1. 实例
      RewriteCond %{HTTP_HOST} "127.0.0.(.*)"		# 这一条RewriteCond有一个正则匹配`(.*)`。将被下一条引用。
      RewriteCond %1 "1"  						# %1 表示上一条RewriteCond的正则匹配的第一个。
      RewriteRule ^(.*)\.htm$ http://localhost/$1.html [R]	# 当URL输入是127.0.0.1的时候,外部重定向为localhost
      
  5. condition pattern
    1. -d 是否是文件夹
    2. -f 是否是文件
    3. -f 是否是文件,且可以访问
  6. [flag]
    1. [OR] 条件判断为“或”。不加就默认为 AND
    2. 实例
      RewriteCond C:/wamp/www -d [OR]
      RewriteCond C:/wamp/www2 -d
      RewriteCond ^(.*)\.htm $1.html
      
5. RewriteMap语法说明
  1. RewriteMap MapType:MapSource
    1. MapName: Map的命名,给RewriteRule调用
    2. MapType: map的文件类型,如 txt、rnd
    3. MapSource: map的文件路径
    4. 在Apache的配置文件里,配置在的外部。
    5. 修改map文件,也不需要重启Apache
  2. txt格式
    1. ${MapName: LookupKey | DefaultValue}
    2. 实例
      # 在`httpd.conf`里面创建一个新的配置项:
      RewriteMap pages txt:C:/wamp/map.txt
      
      # 在C:/wamp/map.txt文件中,保存配置:
      test1 pagetest1
      test2 pagetest2
      
      # 在`.htaccess`中配置,或者在apache的主配置文件中配置
      RewriteRule ^(.*).shtml ${pages:$1|page}.php # $1 表示拿(.*)去配置
      
  3. rnd格式
    1. 随机映射 RewriteMap servers rnd:c:/wamp/rnd.txt
    2. 实例
      # 在`httpd.conf`里面创建一个新的配置项:
      RewriteMap dirs rnd:c:/wamp/dirs.txt
      
      # 在C:/wamp/dirs.txt文件中,保存配置:
      URL1 S1|S2|S3 		# 当访问一个地址,随机抽取一个值。
      URL2 S4|S5
      
      # 在`.htaccess`中配置,或者在apache的主配置文件中配置
      RewriteRule ^(.*).shtml /${dirs:$1|root}/$1.php
      
6. 基础正则
  1. . 任意匹配单个字符。
  2. + 匹配1到多个。
  3. * 匹配0到多个。
  4. ^ 匹配开始位置。
  5. $ 匹配结束位置。
  6. ? 表面前一个匹配项是可选的,可以有也可以无。
  7. [a-z] 匹配一个a-z的字符
  8. [^a-z] 不允许匹配任何a-z的单个字符
  9. | 或者
  10. 取值() $1表示第一个()里面匹配的内容

重定向和伪静态的常用案例

1. 临时重定向和永久重定向
  1. 主要面对的是搜索引擎和机器人。
  2. 301 永久重定向:不是顶级目录的A页面,做301重定向,到其他目录B,则可以正常收录B页面。搜索引擎会把之前的积分算到新的页面。
    1. 例如:公司换域名。
  3. 302 临时重定向:顶级目录的A页面,做302重定向,到其他目录B,则收录的是A页面。
    1. 如果使用,有可能会被搜索引擎认定为SEO作弊。
2. 防止盗链
```
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$ # 允许http_referer为空的情况,用户直接访问图片
RewriteCond %{HTTP_REFERER} !localhost [NC] # 其它http_referer限定访问
RewriteRule \.(gif|jpg|png)$ - [F,NC] # Forbidden访问
```
3. 限制IP列表
```
# httpd.conf
RewriteMap hosts-deny txt:c:/wamp/hosts.deny # 设置一个映射表,列举哪些IP是禁止访问的。

# hosts.deny
192.168.3.68 deny # 禁止IP 和 结果

# .htaccess
# 获取hosts-deny的IP,与%{REMOTE_ADDR}匹配,如果匹配,则会返回'deny'。 
# 由于deny和deny相同,所以RewriteCond为true,则执行RewriteRule的 forbidden。
RewriteEngine on
RewriteCond ${hosts-deny:%{REMOTE_ADDR}|NOTFOUND} deny [OR] 
RewriteCond ${hosts-deny:%{REMOTE_HOST}|NOTFOUND} deny 
RewriteRule ^ - [F] # Forbidden访问
```
4. 限制迅雷
  1. 迅雷访问的特征,USER_AGENT的匹配。
    RewriteCond %{HTTP_USER_AGENT} 2.0.50727 [NC,OR] 	# 迅雷的user agent包含2.0.50727
    RewriteCond %{HTTP_USER_AGENT} ^BlackWido
    RewriteRule . abuse.txt 							# 将迅雷访问重定向到abuse.txt