新睿云

> 知识库 > rewriterule在Apache服务器上http转https配置总结

rewriterule在Apache服务器上http转https配置总结

作者/来源:新睿云小编 发布时间:2019-11-08

开启Rewrite功能

输入以下指令开启Rewrite模组(笔者使用Ubuntu系统)

$ sudo a2enmod rewrite

=> LoadModule rewrite_module modules / mod_rewrite.so

确认是否已经开启模组了

$ sudo apache2ctl -M | grep rewrite

rewrite_module(共享)

随后就可以开始在Site Config里面编写所需的RewriteRule了。

在理解Rewrite的过程中,经常会出现与之搭配的.htaccess档案,.htaccess称为“ 阿帕奇设定的档案(Override Config),简单来说就是可以根据每个资料夹Override原本Site Config,可以针对一个资料夹改写网址,所以RewriteRule .htaccess并非只能只能在其中哦!

但本篇文章还是会以使用.htaccess作为范例,若要打开Override的功能,只要修改Site Config,加入AllowOverride All就可以了(例如/etc/apache2/site-enabled/default000-conf)

<Directory“ / var / www / html”>

AllowOverride All

</ Directory>

全部,FlieInfo都可以让.htaccess使用重写功能,详情可以参考官方设定值的意义。

改写规则

基本用法

就是改写网址条件的规则,它的写法结构如下:

RewriteRule [match_uri] [rewrite_uri] [标志]

match_uri:符合模式的URI

rewrite_uri:将被改写的URI

这两个也都可以使用距离表达式撰写,一个规则范例长这样:

重写^ match / .html $ rewrite.html [NC,L]

意义相等于以下 伪 码:

假设输入网址:http :

//domain.com/a/b/c.html uri = a / b / c.html

if(uri.match(“ match.html”){

url =“ rewrite.html”

}

RewriteRule的标志

最后面的flags代表设定Rule的行为,可用逗号代表多个Flag,中间不能有空格,介绍以下常用的:

[L]:最后一次,代表成功执行这个规则后就会停止,不继续往下执行。

[NC]:不区分大小写,代表match_uri不比对大小写差异。

[QSA]:查询字符串追加,代表保留网址尾端带的GET参数,没使用的标志的预设是会把参数去掉的。

[QSD]:查询字符串丢弃,与QSA相反的作用,apache的V2.4才有。

[R]:重定向,代表用转址的方式转到新的网址,预定是302状态码,如:[R = 301],也可以回传400、200、404等的状态码,通常会跟[L]一起代表结束,也是除错误的常用标志

[DPI]:不要再接续的Rule中结尾中加上PathInfo,会在“五,一些小特性”的伴随说明。

[F]:Forbdien就是不给看啦!

※更多标志:http: //httpd.

范例

接着来举例多个规则,再加上Flag的功用,假设网站资料夹结构如下:

根/

├match.html

├rewrite.html

├的.htaccess

└秘密/

└database_password.json

而范例的.htaccess的内容为:

#前面有井字号是注解

###开启重写

RewriteEngine于

###设置重写前面会补充的路径,预定会是DocumentRoot(如:/ var / www / html)

RewriteBase /

#规则

将由

上往下依序执行

#直到最后一行或遇到有符合且有L标志的规则就会停止

###规则1.输入domain.com/match.html将会显示rewrite.html的内容RewriteRule ^ match / .html $ rewrite.html [NC,L]

###规则2。输入domain.com/redirect.html将被导至domain.com/rewrite.html

RewriteRule ^ redirect / .html $ rewrite.html [NC,R = 302,L]

### Rule 3.如果输入domain.com/secret / ...这样的格式的网址,则去掉secret /后,转回root并加.html

### $ 1是距离表达式的组捕获,就是$ 1 =(。*)取得括号内的值

RewriteRule ^ secret /(.*)$ $ 1.html [NC,L]

在浏览器上输入match.html或redirect.html均会显示rewrite.html的内容,显然是Rule 2将网址更改了,而Rule 1没有,因为就是302状态码的关系。

在此建议可以使用或POSTMAN通过cURL命令列或请求获取取回等工具观察整个响应的差异,将会非常容易除错,详细原因将在“四,如何除错”逐步中解释,以下笔者使用cURL示范:

1.要求:http://localhost/match.html

$

curl'http

://localhost/match.html'

我是rewrite.html

2.要求: http://localhost/redirect.html

$ curl'http ://localhost/redirect.html'

<!DOCTYPE HTML PUBLIC“-// IETF // DTD HTML 2.0 // EN”>

<html> <head>

<title>找到302 </ title>

</ head> <body>

<h1>找到</ h1>

<p>文档已移动<a href=” http://localhost/rewrite.html ">此处</a>。</ p>

<hr>

<地址> Apache / 2.4.33(Win32)OpenSSL / 1.1.0h PHP / 7.2.7位于本地主机端口80的服务器</地址>

</ body> </ html>

与浏览器不同的是,这里的响应会指出网址被转移到另外一个新网址http://localhost/rewrite.html,浏览器自动帮忙处理转定位的工作,根据上面回传的网址,再发出另一个请求获取网页内容,让使用者仅感觉到网址与页面改变而已。

这时候读者可试着把RewriteBase这行注解,将会发现回传结果出错了,

改写结果与Domain之间被加上DocumentRoot预定的路径。

$ curl'http ://localhost/redirect.html'

<!DOCTYPE HTML PUBLIC“-// IETF // DTD HTML 2.0 // EN”>

<html> <head>

<title>找到302 </ title>

</ head> <body>

<h1>找到</ h1>

<p>文档已移到<a href=” http://localhost/var/www/html/rewrite.html ">此处</a>。</ </ p>

<hr>

<地址> Apache / 2.4.33(Win32)OpenSSL / 1.1.0h PHP / 7.2.7位于本地主机端口80的服务器</ address>

</ body> </ html>

```

前面两个Rule仅是一个基本的示范,平常应用当然会难上许多,来继续看第三个Rule吧

### Rule 3.如果输入domain.com/secret / ...这样格式的网址,则去掉secret /后,转回root并添加.html

### $ 1是距离表达式的group capture,就是取得那个满足括号内的值

RewriteRule ^ secret /(.*)$ $ 1.html [NC,L]

第三个规则是禁止使用者访问敏感的secret资料夹,来试着访问database_password.json看能不能得到结果:

$

curl'http

://localhost/secret/database_password.json'HTTP

/ 1.1 404找不到

日期:Sun,2018年10月7日13:39:11 GMT

服务器:Apache / 2.4.33(Win32)OpenSSL / 1.1.0h PHP /7.2.7

变化:accept-language,accept-charset

accept-Ranges:个字节

内容类型:text / html; charset = utf-8

内容语言:zh

不管网址改成任何http://localhost/secret/...,都会回传404找不到頁面,是理想中的状况,非常棒!但是访问反而http://localhost/secret/变成403禁止訪問了耶,咦?

$

curl'http

:// localhost / secret /'

HTTP / 1.1 403 Forbidden

Date:Sun,07 Oct 2018 13:43:08 GMT

Server:Apache / 2.4.33(Win32)OpenSSL / 1.1.0h PHP / 7.2.7

不同:接受语言,接受字符集

接受范围:个字节

内容类型:text / html; charset = utf-8

内容语言:zh

这时候不知出了什么错的话,可以将Rule的Flag加上R=302,检查最后改写的结果出了什么状况:

$ curl'http :// localhost / secret /'

<!DOCTYPE HTML PUBLIC“-// IETF // DTD HTML 2.0 // EN”>

<html> <head>

<title> 302找到</ title>

</ head > <body>

<h1>找到</ h1>

<p>文档已移动<a href=” http://localhost/.html ">此处</a>。</ p>

<hr>

<地址>本地端口80上的Apache / 2.4.33(Win32)OpenSSL / 1.1.0h PHP / 7.2.7服务器</ address>

</ body> </ html>

发现$1没有抓到任何字串,所以没有任何档名加上.html,就变成403的结果,所以只要在Rule 3之前加上以下新的Rule就可以啰!

RewriteRule ^ secret / $ / [R = 302,NC,L]

以上就是RewriteRule与简单的 除错 方法,只要再加上看得懂距离表达式就能理解一般常见的规则啰!继续看更难一点的RewriteCond吧〜

重写条件

RewriteRule仅仅只能判断请求URI是否匹配而改写URI,但有很多需求是希望根据一些请求标头(主机,用户代理)与 阿帕奇 的环境变数做改写,先满足某些条件后,再次重写URI,因此有了RewriteCond的出现,它的写法结构如下:

RewriteCond [test_string] [match_string] [flags]

RewriteRule…

test_string:要比对的条件

match_string:符合的条件

以上这两个都可以使用尺寸表达式撰写,而且RewriteCond结束一定会接着一个RewriteRule,真正的范例会长这样:

RewriteCond%{HTTP_USER_AGENT}(facebookexternalhit)

RewriteRule ^ blog /(.*)$ fb-bot.html?path = $ 1&type =%1 [L]

在以上意义相等于以下 伪 码:

if($ HTTP_USER_AGENT =='facebookexternalhit'){

if(url.match('^ blog /(.*)$')){url</p>

<p>

='fb-bot.html?path = $ 1&type = facebookexternalhit';</p>

<p>

}

}

※前面说到$1是Group Capture的用法,而RewriteCond则是用%1表示

RewriteCond可使用的变数

${HTTP_USER_AGENT}是RewriteCond可使用的变数,有以下常见的变数:

%{REQUEST_URI}:域后面完整的URI路径,规则实际上会拿到不完整的URI,详情可以参考“五,一些小特性”类别

%{QUERY_STRING}:后面GET带的参数

%{HTTP_HOST}:域

% {HTTP_COOKIE}:Cookie

%{HTTPS}:判断是否用https或http,如果是https就等于“ on”,否则为“ off”

%{HTTP_USER_AGENT}:用户代理

%{REQUEST_FILENAME}:访问的档案名称

※更多变量:https :

//httpd.

以及判断档案时,很常见搭配这两个match用法:

-d:目录。代表如果有这个资料夹

-f:常规文件。代表如果有这个档案

搭配起来写法就像以下范例,代表着如果没有这个档案就转到首页:

RewriteCond%{REQUEST_FILENAME}!-f

RewriteRule ^(。*)$ index.html

其实还有不同的match写法,可以参考Apache官网的RewriteCond。

RewriteCond的标志用法

NC:不区分大小写

OR:就是OR条件,下面会说明

RewriteCond也有或遵循AND的条件,先前提到RewriteCond后面一定会接一个RewriteRule,有个特性是它只吃接续的第一个规则,来看下面的范例:

###范例A

RewriteCond 1

RewriteRule 1

RewriteRule 2

//等同于

if(Cond1){

Rule1

}

Rule 2

###范例B

RewriteCond 1

RewriteCond 2

RewriteRule 1

// //等同于

if(Cond1 && Cond2){

Rule1

}

## #范例C

RewriteCond 1 [OR]

RewriteCond 2

RewriteRule 1

//等于于

if(Cond1 || Cond2){

Rule1

}

了解RewriteCond跟RewriteRule的用法与每一行执行下来的逻辑,就可以更容易的改写网路上别人写好的规则啰〜

如何侦错

先前在RewriteRule的先前有稍微简单展示 除错 的流程,这里仅使用文字讲解解一些小秘诀。

1.该使用什么 除错 工具

使用POSTMAN,cURL等的工具,浏览器另外还有Cache外,也会帮忙转址,此时就没办法观察第一次转址的网址内容,例如:最常见就是浏览器直接显示转位太多次的错误,但使用工具的话,就可以看到回应回传的转址结果。

2.如何知道撰写的正则表达式是否正确?

把RewriteRule的标志加[R=302],302状态代码代表Moved Temporarily,浏览器并不会缓存302的转址结果,但301会,可以确定Rule无误后再拿掉或替换原本301就好,像这样观察转址的结果:

RewriteRule ^(。*)$ = $ 1 [L,R = 302]

3.非得要修改正在运行中的网站怎么办?

可以用一些识别的标题,加上RewriteCond来测试撰写的RewriteRule,例如如自定义一个User-agent,每次Reuqest都用这个User-agent即可。

4.浏览器有缓存

前面提到浏览器cache的问题,若认为写的没问题,但访问网站仍是旧有结果的话,就开启私密浏览访问看看,最后仍没办法只好重开 阿帕奇 看看啰。

关于一些小特性

1. RewriteRule在巢状.htaccess当中不会获得完整URI路径

直接看范例,假设资料夹结构如下:

根/

├一个/

├b.html

└htaccess的

├c.html

└htaccess的

###两个htaccess的都只有这一行内容

重写规则^(。*)$ $ 1 [L]

1.要求: c.html

使用root / .htaccess

规则结果:c.html

2.要求: a/b.html

使用root / a / .htaccess

规则结果:b.html

没错,发生了不会拿到a/的路径的情况。

※阿帕奇 会自动选择最接近的.htaccess档案(详情会在下一阶段说明)

3.如果拿掉root/a/.htaccess档案,重新请求:a/b.html

使用root / .htaccess

规则结果:a / b.html

这样的结果又正常了,如果真的想确保拿到完整的URI路径,可以使用%{REQUEST_URL}变数来获得URI啰!

RewriteCond%{REQUEST_URI} ^(。*)$

RewriteRule ^%1 [L]

2. RewriteRule自动附加在结尾的PATH_INFO

有时候会希望遇到Rule1改写之后,再传递至下一个Rule2判断与改写,可是会遇到后面莫名多了先前的URI,来看一个简单的示范例子:

RewriteRule ^(。*)$ web / $ 1 [NC]

RewriteRule ^(。*)$ sec ======= $ 1 ====== [NC,R = 301]

请求: a/b/c.html

经过第一个规则变成:web / a / b / c.html

最后到第二个规则变成:sec ======= web / a / b / c.html / b / c.html ==== ==

发现它在Rule1的结果末端多了一个不需要的/b/c.html,这是因为因为PATH_INFO缘故,若不需要后面Path的话,可以在Rule 1加上DPIFlag移除它,由于一些php的CMS或Framework会使用到PATH_INFO的功能,所以是否关掉PATH_INFO的作用还是要注意一下啰!

3.重新寻找.htaccess档案

有时候要的规则很纯,就只是将所有请求转到都web/资料夹数下:

RewriteBase /

RewriteRule ^(。*)$ web / $ 1 [QSA,L]

但在 阿帕奇2.4后就会遇到出现Redirect Loop的错误,原因是第一次请求URI被改写后成web/xxxx,它会根据新URI找对应最近的.htaccess并再重跑一次RewriteRule

此时有两种解法,第一种是在web/资料夹下放一个空的.htaccess,第二种是可以参考下一点停止Redirect Loop的写法,放在RewriteRule前面。

4.停止重定向循环的情况

有时候会遇到无穷Loop的问题:

由于可能的配置错误,请求超出了10个内部重定向的限制。必要时使用'LimitInternalRecursion'增加限制。使用'LogLevel调试以获取回溯。

可以在所有RewriteRule之前加上判断,若重定向状态是200的话,就停止Loop:

RewriteCond%{ENV:REDIRECT_STATUS} 200

RewriteRule ^-[L]

不过建议还是检查RewriteRule哪边有写错的,毕竟这解不太算是万灵药。

参考:https : //stackoverflow.com/a/20930010

使用Htaccess的缺点

使用Override很方便,.htaccess只要将放到资料夹下面会有效果,但官方实际上不推荐开启Override的功能,它会降低效能,主要是有以下缺点:

1.每次请求的巢状搜寻

每一次请求都会 阿帕奇透过巢状递回的方式搜寻.htaccess档案,导致阿帕奇 缓慢,例如如送出这个请求:

请求: /example/sub/index.html

阿帕奇初步根据路径寻找以下.htaccess档案

/var/www/.htaccess

/var/www/example/.htaccess

/var/www/example/sub/.htaccess

最后 阿帕奇 选择离档案最近的 /var/www/example/sub/.htaccess

性能

2.重复编译RewirteRule

由于每次请求都会巢状搜寻.htaccess,所以再遇到RewriteRule都会重新编译一次,不像Site Config只会编译一次后做缓存,所以RewriteRule非常多的话,也会导致阿帕奇 缓慢。

笔者使用 阿帕奇Benchmark做了一个小型的压力测试,连续访问10000次,同时1000个连线,取其三次执行ab指令的相应,分别比较是否有打开Override功能,并且重写了数量多寡核苷酸有影响,重写了的状况都是以跑到倒数第三行结束为主,且每行RewriteRule跟RewriteCond不重复。

此时上的Total平均值,有开启Override功能还是比没开启花的时间多了一些,而行数的多寡也会影响到花费的时间,但笔者还是有点疑惑,差0.1秒好像也没什么关系呐,这边还有请专业的读者可以为笔者解惑呢QQ

官方认为.htaccess主要还是给无法编辑Site Config的情况下使用,像是一台主机上有多站共享,但真的想用.htaccess效果又不想开启Override的话怎么办呢?也是有一个取得中间值的做法。

在Site Config中预先指定.htaccess档案路径

把Override功能关掉,并使用包括指定.htaccess约会的,如下写法:

的DocumentRoot在/ var / WWW /

<目录/ var / WWW />

设置AllowOverride无

包含/var/www/.htaccess

...

</目录>

但这方法也是有个小缺点:每次更新.htaccess都必须重新启动阿帕奇 重新重新设定。

如果主机流量不大的话,效能问题并没这么严重,最后还是得依据主机上的网站与情况,据估计这样做比较好哦!

热门标签
免费领云产品

免费用

立即领取
联系客服
在线客服   
反馈意见
返回顶部
{{item.description}}

—您的烦恼我们已经收到—

我们会将处理结果发送至您的手机

请耐心等待