]> granicus.if.org Git - apache/blob - docs/manual/rewrite/advanced.html.en
update transformation
[apache] / docs / manual / rewrite / advanced.html.en
1 <?xml version="1.0" encoding="ISO-8859-1"?>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head><!--
4         XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5               This file is generated from xml source: DO NOT EDIT
6         XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7       -->
8 <title>Advanced Techniques with mod_rewrite - Apache HTTP Server</title>
9 <link href="../style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" />
10 <link href="../style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" />
11 <link href="../style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /><link rel="stylesheet" type="text/css" href="../style/css/prettify.css" />
12 <script src="../style/scripts/prettify.js" type="text/javascript">
13 </script>
14
15 <link href="../images/favicon.ico" rel="shortcut icon" /></head>
16 <body id="manual-page"><div id="page-header">
17 <p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/quickreference.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p>
18 <p class="apache">Apache HTTP Server Version 2.5</p>
19 <img alt="" src="../images/feather.gif" /></div>
20 <div class="up"><a href="./"><img title="&lt;-" alt="&lt;-" src="../images/left.gif" /></a></div>
21 <div id="path">
22 <a href="http://www.apache.org/">Apache</a> &gt; <a href="http://httpd.apache.org/">HTTP Server</a> &gt; <a href="http://httpd.apache.org/docs/">Documentation</a> &gt; <a href="../">Version 2.5</a> &gt; <a href="./">Rewrite</a></div><div id="page-content"><div id="preamble"><h1>Advanced Techniques with mod_rewrite</h1>
23 <div class="toplang">
24 <p><span>Available Languages: </span><a href="../en/rewrite/advanced.html" title="English">&nbsp;en&nbsp;</a></p>
25 </div>
26
27
28 <p>This document supplements the <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>
29 <a href="../mod/mod_rewrite.html">reference documentation</a>. It provides
30 a few advanced techniques using mod_rewrite.</p>
31
32 <div class="warning">Note that many of these examples won't work unchanged in your
33 particular server configuration, so it's important that you understand
34 them, rather than merely cutting and pasting the examples into your
35 configuration.</div>
36
37 </div>
38 <div id="quickview"><ul id="toc"><li><img alt="" src="../images/down.gif" /> <a href="#sharding">URL-based sharding accross multiple backends</a></li>
39 <li><img alt="" src="../images/down.gif" /> <a href="#on-the-fly-content">On-the-fly Content-Regeneration</a></li>
40 <li><img alt="" src="../images/down.gif" /> <a href="#load-balancing">Load Balancing</a></li>
41 <li><img alt="" src="../images/down.gif" /> <a href="#autorefresh">Document With Autorefresh</a></li>
42 <li><img alt="" src="../images/down.gif" /> <a href="#structuredhomedirs">Structured Userdirs</a></li>
43 <li><img alt="" src="../images/down.gif" /> <a href="#redirectanchors">Redirecting Anchors</a></li>
44 <li><img alt="" src="../images/down.gif" /> <a href="#time-dependent">Time-Dependent Rewriting</a></li>
45 <li><img alt="" src="../images/down.gif" /> <a href="#setenvvars">Set Environment Variables Based On URL Parts</a></li>
46 </ul><h3>See also</h3><ul class="seealso"><li><a href="../mod/mod_rewrite.html">Module documentation</a></li><li><a href="intro.html">mod_rewrite introduction</a></li><li><a href="remapping.html">Redirection and remapping</a></li><li><a href="access.html">Controlling access</a></li><li><a href="vhosts.html">Virtual hosts</a></li><li><a href="proxy.html">Proxying</a></li><li><a href="rewritemap.html">Using RewriteMap</a></li><li><a href="avoid.html">When not to use mod_rewrite</a></li></ul><ul class="seealso"><li><a href="#comments_section">Comments</a></li></ul></div>
47 <div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
48 <div class="section">
49 <h2><a name="sharding" id="sharding">URL-based sharding accross multiple backends</a></h2>
50
51   
52
53   <dl>
54     <dt>Description:</dt>
55
56     <dd>
57       <p>A common technique for distributing the burden of
58       server load or storage space is called "sharding".
59       When using this method, a front-end server will use the
60       url to consistently "shard" users or objects to separate
61       backend servers.</p>
62     </dd>
63
64     <dt>Solution:</dt>
65
66     <dd>
67       <p>A mapping is maintained, from users to target servers, in
68       external map files. They look like:</p>
69
70 <div class="example"><p><code>
71 user1  physical_host_of_user1<br />
72 user2  physical_host_of_user2<br />
73 :      :
74 </code></p></div>
75
76   <p>We put this into a <code>map.users-to-hosts</code> file. The
77     aim is to map;</p>
78
79 <div class="example"><p><code>
80 /u/user1/anypath
81 </code></p></div>
82
83   <p>to</p>
84
85 <div class="example"><p><code>
86 http://physical_host_of_user1/u/user/anypath
87 </code></p></div>
88
89       <p>thus every URL path need not be valid on every backend physical
90       host. The following ruleset does this for us with the help of the map
91       files assuming that server0 is a default server which will be used if
92       a user has no entry in the map:</p>
93
94 <pre class="prettyprint lang-config">
95 RewriteEngine on
96 RewriteMap      users-to-hosts   txt:/path/to/map.users-to-hosts
97 RewriteRule   ^/u/([^/]+)/?(.*)   http://${users-to-hosts:$1|server0}/u/$1/$2
98 </pre>
99
100     </dd>
101   </dl>
102
103   <p>See the <code class="directive"><a href="../mod/mod_rewrite.html#rewritemap">RewriteMap</a></code>
104   documentation for more discussion of the syntax of this directive.</p>
105
106 </div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
107 <div class="section">
108 <h2><a name="on-the-fly-content" id="on-the-fly-content">On-the-fly Content-Regeneration</a></h2>
109
110   
111
112   <dl>
113     <dt>Description:</dt>
114
115     <dd>
116       <p>We wish to dynamically generate content, but store it
117       statically once it is generated. This rule will check for the
118       existence of the static file, and if it's not there, generate
119       it. The static files can be removed periodically, if desired (say,
120       via cron) and will be regenerated on demand.</p>
121     </dd>
122
123     <dt>Solution:</dt>
124
125     <dd>
126       This is done via the following ruleset:
127
128 <pre class="prettyprint lang-config">
129 # This example is valid in per-directory context only
130 RewriteCond %{REQUEST_URI}   !-U
131 RewriteRule ^(.+)\.html$          /regenerate_page.cgi   [PT,L]
132 </pre>
133
134
135     <p>The <code>-U</code> operator determines whether the test string
136     (in this case, <code>REQUEST_URI</code>) is a valid URL. It does
137     this via a subrequest. In the event that this subrequest fails -
138     that is, the requested resource doesn't exist - this rule invokes
139     the CGI program <code>/regenerate_page.cgi</code>, which generates
140     the requested resource and saves it into the document directory, so
141     that the next time it is requested, a static copy can be served.</p>
142
143     <p>In this way, documents that are infrequently updated can be served in
144     static form. if documents need to be refreshed, they can be deleted
145     from the document directory, and they will then be regenerated the
146     next time they are requested.</p>
147     </dd>
148   </dl>
149
150 </div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
151 <div class="section">
152 <h2><a name="load-balancing" id="load-balancing">Load Balancing</a></h2>
153
154   
155
156   <dl>
157     <dt>Description:</dt>
158
159     <dd>
160       <p>We wish to randomly distribute load across several servers
161       using mod_rewrite.</p>
162     </dd>
163
164     <dt>Solution:</dt>
165
166     <dd>
167       <p>We'll use <code class="directive"><a href="../mod/mod_rewrite.html#rewritemap">RewriteMap</a></code> and a list of servers
168       to accomplish this.</p>
169
170 <pre class="prettyprint lang-config">
171 RewriteEngine on
172 RewriteMap lb rnd:/path/to/serverlist.txt
173 RewriteRule ^/(.*) http://${lb:servers}/$1 [P,L]
174 </pre>
175
176
177 <p><code>serverlist.txt</code> will contain a list of the servers:</p>
178
179 <div class="example"><p><code>
180 ## serverlist.txt<br />
181 <br />
182 servers one.example.com|two.example.com|three.example.com<br />
183 </code></p></div>
184
185 <p>If you want one particular server to get more of the load than the
186 others, add it more times to the list.</p>
187
188    </dd>
189
190    <dt>Discussion</dt>
191    <dd>
192 <p>Apache comes with a load-balancing module -
193 <code class="module"><a href="../mod/mod_proxy_balancer.html">mod_proxy_balancer</a></code> - which is far more flexible and
194 featureful than anything you can cobble together using mod_rewrite.</p>
195    </dd>
196   </dl>
197
198 </div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
199 <div class="section">
200 <h2><a name="autorefresh" id="autorefresh">Document With Autorefresh</a></h2>
201
202   
203
204
205
206   <dl>
207     <dt>Description:</dt>
208
209     <dd>
210       <p>Wouldn't it be nice, while creating a complex web page, if
211       the web browser would automatically refresh the page every
212       time we save a new version from within our editor?
213       Impossible?</p>
214     </dd>
215
216     <dt>Solution:</dt>
217
218     <dd>
219       <p>No! We just combine the MIME multipart feature, the
220       web server NPH feature, and the URL manipulation power of
221       <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>. First, we establish a new
222       URL feature: Adding just <code>:refresh</code> to any
223       URL causes the 'page' to be refreshed every time it is
224       updated on the filesystem.</p>
225
226 <pre class="prettyprint lang-config">
227 RewriteRule   ^(/[uge]/[^/]+/?.*):refresh  /internal/cgi/apache/nph-refresh?f=$1
228 </pre>
229
230
231       <p>Now when we reference the URL</p>
232
233 <div class="example"><p><code>
234 /u/foo/bar/page.html:refresh
235 </code></p></div>
236
237       <p>this leads to the internal invocation of the URL</p>
238
239 <div class="example"><p><code>
240 /internal/cgi/apache/nph-refresh?f=/u/foo/bar/page.html
241 </code></p></div>
242
243       <p>The only missing part is the NPH-CGI script. Although
244       one would usually say "left as an exercise to the reader"
245       ;-) I will provide this, too.</p>
246
247 <pre class="prettyprint lang-perl">
248 #!/sw/bin/perl
249 ##
250 ##  nph-refresh -- NPH/CGI script for auto refreshing pages
251 ##  Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved.
252 ##
253 $| = 1;
254
255 #   split the QUERY_STRING variable
256 @pairs = split( /&amp;/, $ENV{'QUERY_STRING'} );
257 foreach $pair (@pairs) {
258     ( $name, $value ) = split( /=/, $pair );
259     $name =~ tr/A-Z/a-z/;
260     $name = 'QS_' . $name;
261     $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
262     eval "\$$name = \"$value\"";
263 }
264 $QS_s = 1    if ( $QS_s eq '' );
265 $QS_n = 3600 if ( $QS_n eq '' );
266 if ( $QS_f eq '' ) {
267     print "HTTP/1.0 200 OK\n";
268     print "Content-type: text/html\n\n";
269     print "&lt;b&gt;ERROR&lt;/b&gt;: No file given\n";
270     exit(0);
271 }
272 if ( !-f $QS_f ) {
273     print "HTTP/1.0 200 OK\n";
274     print "Content-type: text/html\n\n";
275     print "&lt;b&gt;ERROR&lt;/b&gt;: File $QS_f not found\n";
276     exit(0);
277 }
278
279 sub print_http_headers_multipart_begin {
280     print "HTTP/1.0 200 OK\n";
281     $bound = "ThisRandomString12345";
282     print "Content-type: multipart/x-mixed-replace;boundary=$bound\n";
283     &amp;print_http_headers_multipart_next;
284 }
285
286 sub print_http_headers_multipart_next {
287     print "\n--$bound\n";
288 }
289
290 sub print_http_headers_multipart_end {
291     print "\n--$bound--\n";
292 }
293
294 sub displayhtml {
295     local ($buffer) = @_;
296     $len = length($buffer);
297     print "Content-type: text/html\n";
298     print "Content-length: $len\n\n";
299     print $buffer;
300 }
301
302 sub readfile {
303     local ($file) = @_;
304     local ( *FP, $size, $buffer, $bytes );
305     ( $x, $x, $x, $x, $x, $x, $x, $size ) = stat($file);
306     $size = sprintf( "%d", $size );
307     open( FP, "&lt;$file" );
308     $bytes = sysread( FP, $buffer, $size );
309     close(FP);
310     return $buffer;
311 }
312
313 $buffer = &amp;readfile($QS_f);
314 &amp;print_http_headers_multipart_begin;
315 &amp;displayhtml($buffer);
316
317 sub mystat {
318     local ($file) = $_[0];
319     local ($time);
320
321     ( $x, $x, $x, $x, $x, $x, $x, $x, $x, $mtime ) = stat($file);
322     return $mtime;
323 }
324
325 $mtimeL = &amp;mystat($QS_f);
326 $mtime  = $mtime;
327 for ( $n = 0 ; $n &amp; lt ; $QS_n ; $n++ ) {
328     while (1) {
329         $mtime = &amp;mystat($QS_f);
330         if ( $mtime ne $mtimeL ) {
331             $mtimeL = $mtime;
332             sleep(2);
333             $buffer = &amp;readfile($QS_f);
334             &amp;print_http_headers_multipart_next;
335             &amp;displayhtml($buffer);
336             sleep(5);
337             $mtimeL = &amp;mystat($QS_f);
338             last;
339         }
340         sleep($QS_s);
341     }
342 }
343
344 &amp;print_http_headers_multipart_end;
345
346 exit(0);
347
348 ##EOF##
349 </pre>
350
351     </dd>
352   </dl>
353
354 </div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
355 <div class="section">
356 <h2><a name="structuredhomedirs" id="structuredhomedirs">Structured Userdirs</a></h2>
357
358   
359
360   <dl>
361     <dt>Description:</dt>
362
363     <dd>
364       <p>Some sites with thousands of users use a
365       structured homedir layout, <em>i.e.</em> each homedir is in a
366       subdirectory which begins (for instance) with the first
367       character of the username. So, <code>/~larry/anypath</code>
368       is <code>/home/<strong>l</strong>/larry/public_html/anypath</code>
369       while <code>/~waldo/anypath</code> is
370       <code>/home/<strong>w</strong>/waldo/public_html/anypath</code>.</p>
371     </dd>
372
373     <dt>Solution:</dt>
374
375     <dd>
376       <p>We use the following ruleset to expand the tilde URLs
377       into the above layout.</p>
378
379 <pre class="prettyprint lang-config">
380 RewriteEngine on
381 RewriteRule   ^/~(<strong>([a-z])</strong>[a-z0-9]+)(.*)  /home/<strong>$2</strong>/$1/public_html$3
382 </pre>
383
384     </dd>
385   </dl>
386
387 </div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
388 <div class="section">
389 <h2><a name="redirectanchors" id="redirectanchors">Redirecting Anchors</a></h2>
390
391   
392
393   <dl>
394     <dt>Description:</dt>
395
396     <dd>
397     <p>By default, redirecting to an HTML anchor doesn't work,
398     because mod_rewrite escapes the <code>#</code> character,
399     turning it into <code>%23</code>. This, in turn, breaks the
400     redirection.</p>
401     </dd>
402
403     <dt>Solution:</dt>
404
405     <dd>
406       <p>Use the <code>[NE]</code> flag on the
407       <code>RewriteRule</code>. NE stands for No Escape.
408       </p>
409     </dd>
410
411     <dt>Discussion:</dt>
412     <dd>This technique will of course also work with other
413     special characters that mod_rewrite, by default, URL-encodes.</dd>
414   </dl>
415
416 </div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
417 <div class="section">
418 <h2><a name="time-dependent" id="time-dependent">Time-Dependent Rewriting</a></h2>
419
420   
421
422   <dl>
423     <dt>Description:</dt>
424
425     <dd>
426       <p>We wish to use mod_rewrite to serve different content based on
427       the time of day.</p>
428     </dd>
429
430     <dt>Solution:</dt>
431
432     <dd>
433       <p>There are a lot of variables named <code>TIME_xxx</code>
434       for rewrite conditions. In conjunction with the special
435       lexicographic comparison patterns <code>&lt;STRING</code>,
436       <code>&gt;STRING</code> and <code>=STRING</code> we can
437       do time-dependent redirects:</p>
438
439 <pre class="prettyprint lang-config">
440 RewriteEngine on
441 RewriteCond   %{TIME_HOUR}%{TIME_MIN} &gt;0700
442 RewriteCond   %{TIME_HOUR}%{TIME_MIN} &lt;1900
443 RewriteRule   ^foo\.html$             foo.day.html [L]
444 RewriteRule   ^foo\.html$             foo.night.html
445 </pre>
446
447
448       <p>This provides the content of <code>foo.day.html</code>
449       under the URL <code>foo.html</code> from
450       <code>07:01-18:59</code> and at the remaining time the
451       contents of <code>foo.night.html</code>.</p>
452
453       <div class="warning"><code class="module"><a href="../mod/mod_cache.html">mod_cache</a></code>, intermediate proxies
454       and browsers may each cache responses and cause the either page to be
455       shown outside of the time-window configured.
456       <code class="module"><a href="../mod/mod_expires.html">mod_expires</a></code> may be used to control this
457       effect. You are, of course, much better off simply serving the
458       content dynamically, and customizing it based on the time of day.</div>
459
460     </dd>
461   </dl>
462
463 </div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
464 <div class="section">
465 <h2><a name="setenvvars" id="setenvvars">Set Environment Variables Based On URL Parts</a></h2>
466
467   
468
469   <dl>
470     <dt>Description:</dt>
471
472     <dd>
473       <p>At time, we want to maintain some kind of status when we
474       perform a rewrite. For example, you want to make a note that
475       you've done that rewrite, so that you can check later to see if a
476       request can via that rewrite. One way to do this is by setting an
477       environment variable.</p>
478     </dd>
479
480     <dt>Solution:</dt>
481
482     <dd>
483       <p>Use the [E] flag to set an environment variable.</p>
484
485 <pre class="prettyprint lang-config">
486 RewriteEngine on
487 RewriteRule   ^/horse/(.*)   /pony/$1 [E=<strong>rewritten:1</strong>]
488 </pre>
489
490
491     <p>Later in your ruleset you might check for this environment
492     variable using a RewriteCond:</p>
493
494 <pre class="prettyprint lang-config">
495 RewriteCond %{ENV:rewritten} =1
496 </pre>
497
498
499     <p>Note that environment variables do not survive an external
500     redirect. You might consider using the [CO] flag to set a
501     cookie.</p>
502
503     </dd>
504   </dl>
505
506 </div></div>
507 <div class="bottomlang">
508 <p><span>Available Languages: </span><a href="../en/rewrite/advanced.html" title="English">&nbsp;en&nbsp;</a></p>
509 </div><div class="top"><a href="#page-header"><img src="../images/up.gif" alt="top" /></a></div><div class="section"><h2><a id="comments_section" name="comments_section">Comments</a></h2><div class="warning"><strong>Notice:</strong><br />This is not a Q&amp;A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed again by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Freenode, or sent to our <a href="http://httpd.apache.org/lists.html">mailing lists</a>.</div>
510 <script type="text/javascript"><!--//--><![CDATA[//><!--
511 var comments_shortname = 'httpd';
512 var comments_identifier = 'http://httpd.apache.org/docs/trunk/rewrite/advanced.html';
513 (function(w, d) {
514     if (w.location.hostname.toLowerCase() == "httpd.apache.org") {
515         d.write('<div id="comments_thread"><\/div>');
516         var s = d.createElement('script');
517         s.type = 'text/javascript';
518         s.async = true;
519         s.src = 'https://comments.apache.org/show_comments.lua?site=' + comments_shortname + '&page=' + comments_identifier;
520         (d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s);
521     }
522     else {
523         d.write('<div id="comments_thread">Comments are disabled for this page at the moment.<\/div>');
524     }
525 })(window, document);
526 //--><!]]></script></div><div id="footer">
527 <p class="apache">Copyright 2014 The Apache Software Foundation.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p>
528 <p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/quickreference.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!--
529 if (typeof(prettyPrint) !== 'undefined') {
530     prettyPrint();
531 }
532 //--><!]]></script>
533 </body></html>