项目

通用

个人资料

操作

URL 重写

模块:mod_rewrite

描述

内部重定向,URL 重写

注意:正则表达式匹配是针对完整的 REQUEST_URI 进行的,包括可选的 path-info 和查询字符串。

重写后的 URL 路径结果必须以 '/' 开头(自 1.4.50 版本起强制执行)

选项

url.rewrite-once

在 Web 服务器处理之前,内部重写一组 URL。

url.rewrite-once = ( "<regex>" => "<relative-uri>" )

或对于多个规则
url.rewrite-once = ( 
  "<regex1>" => "<relative-uri1>",
  "<regex2>" => "<relative-uri2>" 
)

url.rewrite-repeat

在 Web 服务器处理之前,内部重写一组 URL

url.rewrite-repeat = ( "<regex>" => "<relative-uri>" )

这些选项之间的区别在于,url.rewrite-repeat 允许连续应用多个(单独定义的)重写规则,而 url.rewrite-once 则会在表达式匹配成功时跳过后续的重写规则。因此,url.rewrite-once 的行为类似于 Apache 的 RewriteRule ... [L]:https://httpd.apache.ac.cn/docs/2.2/mod/mod_rewrite.html#rewriterule

url.rewrite-[repeat-]if-not-file

在 Web 服务器处理之前,内部重写一组 URL,**除非**目标存在且是一个常规文件(不是目录、管道、套接字或其他)。这类似于 Apache 的 !-f RewriteRule。

注意:所有 URL 末尾附加了 path-info 的 URL 都将被视为文件不存在。这在框架中很有用,Lighttpd 应该提供静态文件(存在且是文件的),而其他所有内容都应该重写以使用动态后端,例如 Drupal 或其他 /index.php

url.rewrite-if-not-file 是许多框架的简单解决方案
例如,如果文件存在,则让 Lighttpd 提供静态文件(如 .js、.css、.jpg 等),否则重写以将请求发送到 /index.php
url.rewrite-if-not-file = ( "" => "/index.php?path=${url.path}${qsa}" ) # 选项,如果 index.php 期望在查询字符串 'path=...' 中获取原始 URL
url.rewrite-if-not-file = ( "" => "/index.php${url.path}${qsa}" ) # 备选项,如果 index.php 期望在 PATH_INFO 中获取原始 URL

(作为 mod_rewrite 的替代方案,可以使用 mod_magnet Lua 代码来完全实现 Apache 的 -f 和 -d 解决方案。)

正则表达式

  • . (句点) - 匹配任何字符
  • * (星号) - 匹配前一个符号零次或多次
  • + (加号) - 匹配前一个符号一次或多次
  • ? (问号) - 匹配前一个符号零次或一次
  • \? (反斜杠-某个字符) - 匹配特殊字符
  • ^ (脱字号) - 匹配字符串的开头
  • $ (美元符号) - 匹配字符串的结尾
  • [set] - 匹配方括号内集合中的任一符号。
  • [^set] - 匹配方括号内集合中**不**包含的任何符号。
  • (pattern) - 分组,记住模式匹配到的内容作为一个特殊变量
  • {n,m} - 匹配前一个字符 n 到 m 次(m 可以省略,表示 >=n 次)
  • (?!expression) - 匹配当前位置的任何内容,**但不是**表达式。示例:"^(/(?!(favicon.ico$|js/|images/)).*)" => "/fcgi/$1"
  • 普通的字母数字字符被视为普通字符

替换模式

如果匹配的正则表达式包含括号中的组,替换模式中的 $1..$9 指的是捕获到的文本,其中
匹配组 "$1" 表示第一个组,"$2" 表示第二个,依此类推。

请注意,`url.rewrite-*` 目标中的 % 替换(如 %1、%2、%0 等)是允许的,但它们的含义**与** `evhost.path-pattern` 中的含义**不同**。如果 `url.rewrite-*` 在正则表达式条件中指定,% 模式将替换为条件正则表达式中对应的组。%1 替换为第一个子表达式,%2 替换为第二个,依此类推。%0 替换为匹配正则表达式的整个子字符串。请参阅下面使用“%0”的示例。

扩展替换模式

Lighttpd 提供了在花括号 %{...} 或 ${...} 中编码重定向和重写反向引用替换的方法(自 1.4.50 版本起)

最多保存九 (9) 个匹配项,用于 %{1} - %{9}。最多保存十九 (19) 个匹配项,用于 ${1} - ${19}。

除了 %1 和 $1 之外,现在还支持以下修饰符,后跟反向引用的数字,例如 ${esc:1}。

  • ${noesc:...} 无转义
  • ${esc:...} 转义所有非字母数字字符 - . _ ~ 包括双重转义 %
  • ${escape:...} 转义所有非字母数字字符 - . _ ~ 包括双重转义 %
  • ${escnde:...} 转义所有非字母数字字符 - . _ ~ 但不双重转义 %
  • ${escpsnde:...} 转义所有非字母数字字符 - . _ ~ / 但不双重转义 %(保留字面上的 /)
  • ${tolower:...} 转为小写
  • ${toupper:...} 转为大写
  • ${encb64u:...} 编码为 base64url 字符(无填充)
  • ${decb64u:...} 从 base64url 字符解码
  • %{noesc:...} 无转义
  • %{esc:...} 转义所有非字母数字字符 - . _ ~ 包括双重转义 %
  • %{escape:...} 转义所有非字母数字字符 - . _ ~ 包括双重转义 %
  • %{escnde:...} 转义所有非字母数字字符 - . _ ~ 但不双重转义 %
  • %{escpsnde:...} 转义所有非字母数字字符 - . _ ~ / 但不双重转义 %(保留字面上的 /)
  • %{tolower:...} 转为小写
  • %{toupper:...} 转为大写
  • %{encb64u:...} 编码为 base64url 字符(无填充)
  • %{decb64u:...} 从 base64url 字符解码

Lighttpd 提供了一些预定义的替换模式,用于 URI 部分,无需正则表达式匹配(自 1.4.50 版本起)

  • ${url.scheme} 例如 https
  • ${url.authority} 例如 example.com
  • ${url.port} 例如 443
  • ${url.path} 例如 /robots.txt
  • ${url.query} 例如 name1=value1&name2=value2
  • ${qsa} 会智能地转换为 ?${url.query}&${url.query} 或空字符串,具体取决于源或目标 URL 中的查询字符串是否为空

替换模式可以与编码修饰符结合使用,例如 ${tolower:url.authority}。

示例

注意:正则表达式匹配是针对完整的 REQUEST_URI 进行的,包括可选的 path-info 和查询字符串。

# The following contrived example, is just simulating vhost by rewrite
# (Note: you can not change document-root with mod_rewrite)
# Use mod_simple_vhost, mod_evhost, or mod_vhostdb instead to make real mass-vhost

# Since lighttpd 1.4.50

server.document-root = "/www/htdocs/" 
url.rewrite-once = ( "" => "/${url.authority}/$0" )
# The "" on the left side of => is special for mod_rewrite and always matches the full url,
# and $0 contains the full url.

# Before lighttpd 1.4.50

server.document-root = "/www/htdocs/" 
$HTTP["host"] =~ "^.*\.([^.]+\.com)$" {
  url.rewrite-once = ( "^/(.*)" => "/%0/$1" )
}

# request:        http://any.domain.com/url/ 
# before rewrite: REQUEST_URI="/www/htdocs/url/" 
# and DOCUMENT_ROOT="/www/htdocs/" %0="any.domain.com" $1="url/" 
# after rewrite:  REQUEST_URI="/www/htdocs/any.domain.com/url/" 
# still, you have DOCUMENT_ROOT=/www/htdocs/

# please note, that we have two regular expressions: the one which 
# $HTTP["host"] is been compared with, and the one of the rewrite rule.
# the numbered subexpressions available to build the relative uri are
# being prefixed by '%' for subexpressions of the first regular expression 
# match and by '$' for subexpressions of the second one.
# subexpression 0 interpolates the whole matching string: %0 for the whole
# string matching the conditional, and $0 for the whole string matching the
# rewrite rule.

# if the rewrite rule is not included in a conditional 
# block, only the '$' prefixed variables are available.

url.rewrite-once = ( "^/id/([0-9]+)$" => "/index.php?id=$1",
                     "^/link/([a-zA-Z]+)" => "/index.php?link=$1" )

与 mod_redirect 配合使用

重写规则始终在重定向规则之前执行。无论模块加载顺序或配置中规则的顺序如何,这都成立(Lighttpd v1.4.13)。但是,mod_rewrite 提供了一种机制,可以使 URL 不被修改地通过:将 "$0" 指定为规则目标,但请确保规则匹配整个字符串,因为 $0 是整个匹配的字符串。

url.rewrite-once = (
    "^/foo"  => "$0",
    "^/(.*)" => "/handler/$1" 
)

url.redirect = (
    "^/foo"  => "http://foo.bar/" 
)

自版本 1.4.40 起,另一种替代方法是为重写规则指定一个空目标。这将使匹配的规则保持 URL 未修改,并跳过任何后续的重写规则。

url.rewrite-once = (
    "^/foo"  => "",   # instead of (nonsensical) blank url, the url will not be modified
    "^/(.*)" => "/handler/$1" 
)

Windows 上“文件名过长”的解决方法

在 Windows 上运行 Lighttpd 时,如果计算出的文件名长度超过 255 个字符,您可能会收到 500 Internal Server Error
在错误日志中,它将显示为 (response.c.537) file not found ... or so: File name too long /very_looooong_path ->
作为变通方法,您可以使用 mod_rewrite 来避免此错误。

server.modules += ("mod_rewrite")
url.rewrite-once = ( ".{250,}" => "/toolong.php" )

如果错误处理器是 PHP,$_SERVER['REQUEST_URI'] 将包含完整的 URI。

传递/匹配查询字符串(GET 变量)

如果您想将查询字符串(?foo=bar)传递到重写目标,您可以在 Lighttpd 的现代版本中使用 ${qsa}("qsa" 是 "query-string-append" 的缩写)
url.rewrite-once = ( "^/news/([^\?]+)" => "/news.php?title=$1${qsa}" )
对于 Lighttpd 的旧版本,您可能需要明确匹配查询字符串
url.rewrite-once = ( "^/news/([^\?]+)(?:\?(.*))?" => "/news.php?title=$1&$2" )

gstrauss11 个月前更新 · 64 次修订