Apache 和 Nginx 下的 URL 重写

image

URL 重写和重定向

URL 重写是将页面映射到本站另外一页面, 而重定向则是将页面映射到另外一主机(域名). 其中临时重定向(R=302)和永久重定向(R=301)都是亲搜索引擎的, 是 SEO 的重要技术. 经过重定向, 浏览器和搜索引擎都意思到页面发生了变化, 从而分别改变地址栏显示的地址和更新搜索引擎索引。php

Apache 中的 URL 重写和重定向

启用Apache 的 URL 重写功能, 须要开启mod_rewrite模块.。而后在服务器配置文件或htaccess中修改服务配置:html

AllowOverride all
Options FollowSysLinks

服务器配置文件和htaccess文件中均可以配置 URL 重写,前者是服务器级别, 后者是目录级别。web

开启重写日志

2.4 如下版本正则表达式

在Apache 服务器配置文件中追加:apache

`RewriteLog "自定义日志路径"
# 设置日志等级
RewriteLogLevel 9`api

等级0 为关闭, 9 表示输出最详细信息。浏览器

2.4 及其以上版本安全

在Apache 服务器配置文件中追加:服务器

LogLevel alert rewrite:trace3cookie

其中trace3 能够替换为 trace1 到 trace8, 数值越大输出的信息越详细. 最后输出的日志信息在apache_error.log文件中.

注意: 日志级别越高, 越影响服务器性能. 生产环境下应关闭重写日志.

重写指令

RewriteEngine

RewriteEngine: 是否启用重写引擎. On启用, Off不启用.

RewriteBase

RewriteBase: 设置重写的基准目录. 基准目录的根目录就是网站的根目录.

RewriteCond

RewriteCond: 设置重写条件.

语法: 

RewriteCond TestString CondPattern \[flags\]

RewriteCond 指令定义一条规则条件。

在一条 RewriteRule 指令前面可能会有一条或多条 RewriteCond 指令,只有 TestString 符合 CondPattern 时规则才被应用于当前URL处理。

1) TestString是一个纯文本的字符串,除了包含普通的字符外,还能够包括下列的可扩展结构:

$N: RewriteRule 后向引用,其中(0 <= N <= 9) . $N引用紧跟在 RewriteCond 后面的 RewriteRule 中模板中的括号中的模板在当前 URL 中匹配的数据。

%N: RewriteCond 后向引用, 其中(0 <= N <= 9). %N引用最后一个 RewriteCond 的模板中的括号中的模板在当前 URL 中匹配的数据。

${mapname:key|default}:RewriteMap 扩展。

2) CondPattern是条件 pattern, 即一个应用于当前实例TestString 的正则表达式, 即 TestString 将会被计算而后与CondPattern 匹配. 做为一个标准的扩展正则式, CondPattern 有如下补充:

能够在模板串前增长一个!前缀,以表示不匹配模板。但并非全部的 test 均可以加!前缀。

CondPattern中可使用如下特殊变量:

>CondPattern: 大于, 将 CondPattern 看成一个普通字符串, 将它和 TestString 进行比较, 当T estString 的字符大于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]是第三个参数,多个标志之间用逗号分隔。

nocase|NC:不区分大小写. 在扩展后的 TestString 和 CondPattern 中, 比较时不区分文本的大小写. 注意, 这个标志对文件系统和 subrequest 检查没有影响.

ornext|OR:创建与下一个条件的或的关系. 默认的状况下,二个条件之间是AND的关系, 用这个标志将关系改成OR. 例如:

RewriteCond %{REMOTE_HOST} ^host1.* [OR] RewriteCond %{REMOTE_HOST} ^host2.* [OR] RewriteCond %{REMOTE_HOST} ^host3.* RewriteRule …

若是没有[OR]标志,须要写三个条件/规则。

RewriteRule

RewriteRule:设置重写规则.

语法

RewriteRule Pattern Substitution [flags].

1) Pattern是一个做用于当前 URL 的兼容 perl 的正则表达式. 这里的“当前”是指该规则生效时的 URL 的值。

2) Substitution是当原始 URL 与 Pattern 相匹配时, 用以替代(或替换)的字符串. (RewriteRule 中也会进行一次判断, 被捕获的 URL 是否与 Pattern相匹配)

3) Substitution还能够追加特殊标记[flags]做为 RewriteRule 指令的第三个参数。 Flags 是一个包含以逗号分隔的下列标记的列表:

1.redirect|R[=code] (强制重定向 redirect)
强制性执行一个外部重定向. 若是code没有指定, 则默认302. 若是须要使用在 300-400 范围内的其余响应代码, 只需在此指定这个数值便可。

另外, 还可使用下列符号名称之一: temp(默认的), permanent, seeother.

注意:在使用这个标记时,务必确保该替换字段是一个有效的 URL ! 而且要记住,若是但愿中止重写操做而当即重定向,则还须要使用L标记。

2.forbidden|F(强制 URL 为被禁止的 forbidden )

强制当前URL 为被禁止的, 当即反馈一个 403. 使用这个标记, 能够连接若干 RewriteConds 以有条件地阻塞某些 URL。

3.gone|G(强制 URL 为已废弃的 gone )

强制当前URL 为已废弃的, 当即反馈一个 410. 使用这个标记, 能够标明页面已经被废弃而不存在了。

4.proxy|P(强制为代理 proxy )

此标记使替换成分被内部强制为代理请求, 并当即(重写规则处理当即中断)把处理移交给代理模块. 你必须确保此替换串是一个有效的, 可以为 Apache 代理模块所处理的 URI. 使用这个标记, 能够把某些远程成分映射到本地服务器名称空间, 从而加强了 ProxyPass 指令的功能。

注意:要使用这个功能, 代理模块必须编译在Apache服务器中. 不能肯定, 能够检查httpd -l的输出中是否有mod_proxy.c. 若是有, 则mod_rewrite可使用这个功能; 若是没有, 则必须启用mod_proxy并从新编译httpd程序.

5.last|L(最后一个规则 last)

当即中止重写操做, 并再也不应用其余重写规则. 它对应于 Perl中 的last命令或C语言中的break命令. 这个标记能够阻止当前已被重写的 URL 为其后继的规则所重写.

6.next|N(从新执行 next round)

从新执行重写操做(从第一个规则从新开始). 这时再次进行处理的URL已经不是原始的URL, 而是经最后一个重写规则处理的URL. 它对应于 Perl 中的next命令或C语言中的continue命令. 此标记能够从新开始重写操做, 即当即回到循环的头部.

7.chain|C(与下一个规则相连接 chained)

此标记使当前规则与下一个(其自己又能够与其后继规则相连接的, 并能够如此反复的)规则相连接. 它产生这样一个效果: 若是一个规则被匹配, 一般会继续处理其后继规则, 即这个标记不起做用; 若是规则不能被匹配, 则其后继的连接的规则会被忽略. 好比, 在执行一个外部重定向时, 对一个目录级规则集, 你可能须要删除".www" (此处不该该出现".www"的).

8.type|T=MIME-type(强制MIME类型 type)

强制目标文件的MIME 类型为 MIME-type. 好比, 它能够用于模拟 mod_alias 中的 ScriptAlias 指令, 在内部强制被映射目录中的全部文件的 MIME 类型为"application/x-httpd-cgi".

9.nosubreq|NS(仅用于不对内部子请求进行处理 no internal sub-request)

在当前请求是一个内部子请求时, 此标记强制重写引擎跳过该重写规则. 好比, 在 mod_include 试图搜索可能的目录默认文件(http://index.xxx)时, Apache 会在内部产生子请求. 对子请求, 它不必定有用的, 并且若是整个规则集都起做用, 它甚至可能会引起错误. 因此, 能够用这个标记来排除某些规则.

10.nocase|NC(忽略大小写 no case)

它使Pattern 忽略大小写。

11.qsappend|QSA(追加请求串 query string append)

此标记强制重写引擎在已有的替换串中追加一个请求串, 而不是简单的替换. 若是须要经过重写规则在请求串中增长信息, 就可使用这个标记。

12.noescape|NE(在输出中不对URI做转义 no URI escaping)

此标记阻止mod_rewrite 对重写结果应用常规的 URI 转义规则. 通常状况下, 特殊字符(如%, $, ;等)会被转义为等值的十六进制编码. 此标记能够阻止这样的转义, 容许百分号等符号出如今输出中,如:

RewriteRule /foo/(.*) /bar?arg=P1=$1 [R,NE] 可使’/foo/zed’转向到一个安全的请求’/bar?arg=P1=zed’.

13.passthrough|PT(移交给下一个处理器 pass through)

让mod_rewrite 模块将重写的 URL 传回给 Apache 作进一步处理。

14.skip|S=num(跳事后继的规则 skip)

若是知足某指定的条件,则跳事后面第num 调规则。

15.env|E=variable:value(设置环境变量 environment variable)

此标记使环境变量variable 的值为 value, VAL能够包含可扩展的反向引用的正则表达式$N和%N. 此标记能够屡次使用以设置多个变量。这些变量能够在后继的 RewriteCond 指令的pattern 中经过%{ENV:VAR}做引用 。

16.cookie|CO=NAME:VAL:domain[:lifetime[:path]](设置cookie)

在客户端浏览器上设置一个cookie. cookie 的名称是 NAME, 值是 VAL. domain字段是该 cookie 的域, 好比'.apache.org', 可选的 lifetime 是 cookie 生命期的分钟数, 可选的 path 是 cookie 的路径。

attachments-2020-04-5a3z3CG05e8e82e678784.jpg

在.htaccess 文件中配置重写规则

在.htaccess文件中使用重写功能时, RewriteRule 负责匹配的 URI 是相对.htaccess所在的目录而言的。

例如访问http://example.com/subdir1/su...:

  • 若是.htaccess在网站根目录下, 那么RewriteRule捕获的 URI 是subdir1/subdir2/subdir3.
  • 若是.htaccess在 subdir1 目录下, RewriteRule捕获的 URI 是subdir2/subdir3.

RewriteRule重写 URI 后的基准目录也是以.htaccess所在的目录为准. 例如: 访问 http://example.com/foo

RewriteRule ^foo$ bar.php [L]

若是.htaccess在根目录下, 重写后访问 http://example.com/bar.php. 若是在 subdir1 目录下, 重写后访问 http://example.com/subdir1/ba...

例1:

<IfModule mod_rewrite.c># 启用rewrite引擎RewriteEngine On# 重写规则: 匹配任意以htm后缀的文件, 将htm替换成php. ^(.*)\.htm$ 是一个正则表达式, 表示须要重写的部分, 此处指以任意字符开头, 以.htm结尾的部分. $1.php 是一个重写规则, $1 表示匹配到正则表达式中第一个子模式的字符串. [NC]: 表示重写规则如何应用, 该处表示不区分大小写. 整条规则即重写以任意字符开头, 以.htm结尾的部分, 重写为由匹配到的第一个子模式字符串和.php拼接成的字符串。RewriteRule ^(.*)\.htm$ $1.php [NC]</IfModule>

IfModule 命令用于判断是否安装了 mod_rewrite 模块。

例2:

<IfModule mod_rewrite.c>RewriteEngine On# 设置目录级重写的基准URIRewriteBase /subdir1/RewriteRule ^(.*)\.htm$ $1.php [NC,L,R]</IfModule>
  • RewriteBase设置了重写的基准目录. 若是上例中.htaccess位于网站根目录下, 访问的 http://example.com/foo.htm, 本来重写后的基准目录是网站根目录/, 设置了RewriteBase后变为/subdir1/, 重写后实际访问 http://example.com/subdir1/fo...
  • 规则标志L: 表示若是能够匹配本条规则, 则再也不继续往下匹配.
  • 规则标志R: 表示临时重定向, 即 302, 至关于[R=302]。

例3:

<IfModule mod\_rewrite.c><IfModule mod\_rewrite.c>RewriteEngine OnRewriteCond %{HTTP\_HOST} (localhost:81)RewriteRule ^(.\*) http://localhost:82 \[R=301\]</IfModule>

  • [R=301]: 表示永久性重定向, 用户发送的全部请求都会被发送到新域名处理,永久重定向到另外一个域名使用了绝对 URI, 所以不用再设置 RewriteBase。
  • %{HTTP_HOST}:表示引用 Apache 服务器变量 HTTP_HOST。
  • 该条RewriteCond 表示判断 HTTP_HOST 是不是 localhost:81。

在httpd.conf 中配置重写规则

在服务器配置文件中配置URL 重写的指令与 .htaccess 文件中的格式相同,须要写在<Directory>内.

Nginx

Nginx 的 URL 重写功能不须要额外的支持. Nginx 自己只支持在服务器配置文件中配置 URL 重写规则, 不支持 .htaccess 文件. 但能够经过在服务器配置文件中引入外部文件的方式, 实现对 .htaccess 文件的支持. 这会严重影响 Nginx 的性能。

重写指令

rewrite

根据重写规则, 重写 URL。

语法:

rewrite regex replacement flag

应用环境: server, location, if

可应用的flag 标记包括:

  • last:至关于 Apache 中的L标记。
  • break:终止匹配, 再也不匹配后面的规则。
  • redirect:临时重定向, 返回 302。
  • permanent:永久性重定向, 返回 301。

示例:

rewrite ^(.*)\.html$ $1.php last;

注意:若是访问的是 http://localhost/dir/file, rewrite 中的正则表达式匹配的是 /dir/file, 包括最左边的正斜杠.

if 指令

语法: 

if (condition){...}

注意if以后紧跟的空格不能省略。

应用环境:server, location

判断一个条件是否符合, 若是符合, 则执行大括号内语句. if 指令不支持嵌套, 不支持&&和||操做。

condition中能够包含以下判断表示:

  • ~: 区分大小写进行匹配
  • ~*: 不区分大小写进行匹配
  • !~: 区分大小写进行非匹配
  • !~*: 不区分大小写进行非匹配
  • -f: 若是文件存在
  • !-f: 若是文件不存在
  • -d: 若是目录存在
  • !-d: 若是目录不存在
  • -e: 若是文件或目录存
  • !-e: 若是文件或目录不存在
  • -x: 若是文件可执行
  • !-x: 若是文件不可执行

示例:

location ~ \.html$ {if (!\-f $request_filename){rewrite (.*)\.html$ $1.php last;}}

访问的URL 以.html结尾时, 判断是否存在该文件, 若是不存在就重写为访问同名的 PHP 脚本。

return 指令

语法:

return code复制代码

应用环境:server, location, if

该指令用于结束规则的执行并返回状态码给客户端。

例如:

return 403;

location 指令

语法: 

location [flags] regex

应用环境: server

flags 包括:

  • ~: 执行一个正则匹配, 区分大小写
  • ~*: 执行一个正则匹配, 不区分大小写
  • ^~: 表示普通字符匹配. 使用前缀匹配成功. 若是匹配成功, 则再也不匹配其余 location.
  • =: 进行普通字符彻底匹配.

优先级:

  • =的优先级最高. 匹配成功后, 再也不匹配其余项.
  • ^~类型表达式. 匹配成功后, 再也不匹配其余项.
  • ~和~*. 若是有多个 location 的正则匹配.
  • 常规字符串匹配类型, 按前缀匹配.

rewrite_log 指令

语法: 

rewrite_log on|off

应用环境:server, location, if

启用时, 将在error_log中记录 notice 级别的重写日志.

set 指令

语法:

set variable value

应用环境:server, location, if

为给定的变量设置一个特定值。

Nginx 内置的全局变量

$args: 这个变量等于请求行中的参数, 同 $query_string.

  • $content_length: 请求头中的 Content-length 字段.
  • $content_type: 请求头中的 Content-Type 字段.
  • $document_root: 当前请求在 root 指令中指定的值.
  • $host: 请求主机头字段,不然为服务器名称.
  • $http_user_agent: 客户端 agent 信息.
  • $http_cookie: 客户端 cookie 信息.
  • $limit_rate: 这个变量能够限制链接速率.
  • $request_method: 客户端请求的动做,一般为 GET 或 POST.
  • $remote_addr: 客户端的 IP 地址.
  • $remote_port: 客户端的端口.
  • $remote_user: 已经通过 Auth Basic Module 验证的用户名.
  • $request_filename: 当前请求的文件路径, 由 root 或 alias 指令与 URI 请求生成.
  • $scheme: HTTP 方法(如 http, https).
  • $server_protocol: 请求使用的协议, 一般是HTTP/1.0 或 HTTP/1.1.
  • $server_addr: 服务器地址, 在完成一次系统调用后能够肯定这个值.
  • $server_name: 服务器名称.
  • $server_port: 请求到达服务器的端口号.
  • $request_uri: 包含请求参数的原始 URI, 不包含主机名, 如: ”/foo/bar.php?arg=baz”.
  • $uri: 不带请求参数的当前 URI, $uri 不包含主机名, 如 "/foo/bar.html".
  • $document\_uri: 与$uri相同.

1

相关文章
相关标签/搜索