<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>idea&#039;s blog &#187; mod_rewrite</title>
	<atom:link href="http://www.ideawu.net/blog/tag/mod_rewrite/feed" rel="self" type="application/rss+xml" />
	<link>http://www.ideawu.net/blog</link>
	<description>网络服务器架构, Linux C/C++服务器端开发, TCP/IP网络协议, PHP Web后端和Web前端开发, 网站架构.</description>
	<lastBuildDate>Wed, 08 Feb 2012 10:02:48 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>链接包含&#8221;%2F&#8221;导致mod_rewrite失效</title>
		<link>http://www.ideawu.net/blog/archives/494.html</link>
		<comments>http://www.ideawu.net/blog/archives/494.html#comments</comments>
		<pubDate>Wed, 05 May 2010 02:05:09 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[mod_rewrite]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/archives/494.html</guid>
		<description><![CDATA[<p>IT牛人博客聚合网站(<a href="http://www.udpwork.com/">www.udpwork.com</a>)用到了 Apache 的 mod_rewrite 模块进行 URL 重写. 但是, 在使用过程中曾经出现过一个比较诡异的问题. 开始认为是重写规则设置得不对, 后来才发现, 是&#8221;%2F&#8221;导致 Apache 直接返回 404 错误.</p>
<p>比如浏览查看某个标签下的文章列表的链接为</p>
<pre>

http://www.udpwork.com/tag/Linux
</pre>
<p>在重写之前的链接是</p>
<pre>

http://www.udpwork.com/?tag=Linux
</pre>
<p><span id="more-494"></span></p>
<p>在 <a href="http://www.ideawu.net/blog/category/web/php">PHP</a> 脚本中用如下代码重写 URL</p>
<pre>
$url = '/tag/' . urlencode($tag);
</pre>
<p>相应的 Apache mod_rewrite 配置为</p>
<pre>
RewriteCond  %{REQUEST_URI}  ^/tag/.*$
RewriteRule  ^/tag/(.*)$  ?tag=$1  [L]
</pre>
<p>不过, 当 tag 中包含斜杠&#8217;/'时, 出现了问题, 服务器提示&#8221;404 &#8211; Not Found&#8221;. 比如 tag 是 Unix/Linux, 生成的链接是</p>
<pre>

http://www.udpwork.com/tag/Unix%2FLinux
</pre>
<p>斜杠&#8217;/'被转义成&#8217;%2F&#8217;, 那么最终的还原后的链接应该是</p>
<pre>

http://www.udpwork.com/?tag=Unix%2FLinux
</pre>
<p>直接访问这个未重写过的 URL, 是完全正常的. 但 Apache 一直报 404 错误. 后来才发现, 原来 Apache 有一个配置项&#8221;<a href="http://httpd.apache.org/docs/2.0/mod/core.html#allowencodedslashes">AllowEncodedSlashes</a>&#8220;, 默认是&#8221;Off&#8221;, 也就是不允许请求路径(上例是 /tag/Unix%2FLinux)中包含编码后的斜杠&#8217;/'(在某些平台是反斜杠&#8217;\'). 这个选项的的相应代码在 mod_rewrite 模块被执行之前</p>
<pre>
// request.c
AP_DECLARE(int) ap_process_request_internal(request_rec *r){
	if (d->allow_encoded_slashes) {
		access_status = ap_unescape_url_keep2f(r->parsed_uri.path);
	} else {
		access_status = ap_unescape_url(r->parsed_uri.path);
	}
}

// util.c
AP_DECLARE(int) ap_unescape_url(char *url){
	if (IS_SLASH(*x) || *x == '\0')
		badpath = 1;
	...
	else if (badpath)
		return HTTP_NOT_FOUND;
}
</pre>
<p>默认不允许包含&#8221;%2F&#8221;. 如果请求路径中包含了, 那么 ap_unescape_url() 函数认为是无效的路径, 直接返回 HTTP_NOT_FOUND, 最终浏览器得到的是&#8221;404 &#8211; Not Found&#8221;出错页面. 当然可以通过修改 Apache 配置来解决这个问题, 不过, 在 PHP 脚本中解决更通用</p>
<pre>
$url = '/tag/' . urlencode(str_replace('/', '%2F', $tag));
</pre>
<p>这样, 斜杠被两次转义, 变为&#8221;/tag/Unix%252FLinux&#8221;. Apache 接收到请求后, 进行一次解码, 得到&#8221;/tag/Unix%2FLinux&#8221;, 以参数&#8221;tag=Unix%2FLinux&#8221;交给 PHP 脚本处理, PHP 自己再将请求参数进行一次解码, $_GET['tag'] 的值就是&#8221;Unix/Linux&#8221;了.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/618.html' rel='bookmark' title='Permanent Link: Apache用mod_rewrite配置子域名'>Apache用mod_rewrite配置子域名</a></li>
<li><a href='http://www.ideawu.net/blog/archives/460.html' rel='bookmark' title='Permanent Link: 我为什么要放弃订阅转而做牛人博客聚合'>我为什么要放弃订阅转而做牛人博客聚合</a></li>
<li><a href='http://www.ideawu.net/blog/archives/214.html' rel='bookmark' title='Permanent Link: Web设计与开发服务'>Web设计与开发服务</a></li>
<li><a href='http://www.ideawu.net/blog/archives/539.html' rel='bookmark' title='Permanent Link: 调查: 你认为IT牛人博客聚合网站应该提供RSS吗?'>调查: 你认为IT牛人博客聚合网站应该提供RSS吗?</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/494.html" title="链接包含&#8221;%2F&#8221;导致mod_rewrite失效">链接包含&#8221;%2F&#8221;导致mod_rewrite失效</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>IT牛人博客聚合网站(<a href="http://www.udpwork.com/">www.udpwork.com</a>)用到了 Apache 的 mod_rewrite 模块进行 URL 重写. 但是, 在使用过程中曾经出现过一个比较诡异的问题. 开始认为是重写规则设置得不对, 后来才发现, 是&#8221;%2F&#8221;导致 Apache 直接返回 404 错误.</p>
<p>比如浏览查看某个标签下的文章列表的链接为</p>
<pre>

http://www.udpwork.com/tag/Linux
</pre>
<p>在重写之前的链接是</p>
<pre>

http://www.udpwork.com/?tag=Linux
</pre>
<p><span id="more-494"></span></p>
<p>在 <a href="http://www.ideawu.net/blog/category/web/php">PHP</a> 脚本中用如下代码重写 URL</p>
<pre>
$url = '/tag/' . urlencode($tag);
</pre>
<p>相应的 Apache mod_rewrite 配置为</p>
<pre>
RewriteCond  %{REQUEST_URI}  ^/tag/.*$
RewriteRule  ^/tag/(.*)$  ?tag=$1  [L]
</pre>
<p>不过, 当 tag 中包含斜杠&#8217;/'时, 出现了问题, 服务器提示&#8221;404 &#8211; Not Found&#8221;. 比如 tag 是 Unix/Linux, 生成的链接是</p>
<pre>

http://www.udpwork.com/tag/Unix%2FLinux
</pre>
<p>斜杠&#8217;/'被转义成&#8217;%2F&#8217;, 那么最终的还原后的链接应该是</p>
<pre>

http://www.udpwork.com/?tag=Unix%2FLinux
</pre>
<p>直接访问这个未重写过的 URL, 是完全正常的. 但 Apache 一直报 404 错误. 后来才发现, 原来 Apache 有一个配置项&#8221;<a href="http://httpd.apache.org/docs/2.0/mod/core.html#allowencodedslashes">AllowEncodedSlashes</a>&#8220;, 默认是&#8221;Off&#8221;, 也就是不允许请求路径(上例是 /tag/Unix%2FLinux)中包含编码后的斜杠&#8217;/'(在某些平台是反斜杠&#8217;\'). 这个选项的的相应代码在 mod_rewrite 模块被执行之前</p>
<pre>
// request.c
AP_DECLARE(int) ap_process_request_internal(request_rec *r){
	if (d->allow_encoded_slashes) {
		access_status = ap_unescape_url_keep2f(r->parsed_uri.path);
	} else {
		access_status = ap_unescape_url(r->parsed_uri.path);
	}
}

// util.c
AP_DECLARE(int) ap_unescape_url(char *url){
	if (IS_SLASH(*x) || *x == '\0')
		badpath = 1;
	...
	else if (badpath)
		return HTTP_NOT_FOUND;
}
</pre>
<p>默认不允许包含&#8221;%2F&#8221;. 如果请求路径中包含了, 那么 ap_unescape_url() 函数认为是无效的路径, 直接返回 HTTP_NOT_FOUND, 最终浏览器得到的是&#8221;404 &#8211; Not Found&#8221;出错页面. 当然可以通过修改 Apache 配置来解决这个问题, 不过, 在 PHP 脚本中解决更通用</p>
<pre>
$url = '/tag/' . urlencode(str_replace('/', '%2F', $tag));
</pre>
<p>这样, 斜杠被两次转义, 变为&#8221;/tag/Unix%252FLinux&#8221;. Apache 接收到请求后, 进行一次解码, 得到&#8221;/tag/Unix%2FLinux&#8221;, 以参数&#8221;tag=Unix%2FLinux&#8221;交给 PHP 脚本处理, PHP 自己再将请求参数进行一次解码, $_GET['tag'] 的值就是&#8221;Unix/Linux&#8221;了.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/618.html' rel='bookmark' title='Permanent Link: Apache用mod_rewrite配置子域名'>Apache用mod_rewrite配置子域名</a></li>
<li><a href='http://www.ideawu.net/blog/archives/460.html' rel='bookmark' title='Permanent Link: 我为什么要放弃订阅转而做牛人博客聚合'>我为什么要放弃订阅转而做牛人博客聚合</a></li>
<li><a href='http://www.ideawu.net/blog/archives/214.html' rel='bookmark' title='Permanent Link: Web设计与开发服务'>Web设计与开发服务</a></li>
<li><a href='http://www.ideawu.net/blog/archives/539.html' rel='bookmark' title='Permanent Link: 调查: 你认为IT牛人博客聚合网站应该提供RSS吗?'>调查: 你认为IT牛人博客聚合网站应该提供RSS吗?</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/494.html" title="链接包含&#8221;%2F&#8221;导致mod_rewrite失效">链接包含&#8221;%2F&#8221;导致mod_rewrite失效</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/494.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

