条件请求头¶
模块:mod_setenv
描述¶
mod_setenv 修改请求头(来自客户端)、响应头(到客户端)以及环境变量(用于 CGI)。
注意:mod_setenv 需要在 lighttpd.conf 的 server.modules
列表中列在 mod_redirect 之前,以便 mod_setenv 可以在重定向之前设置头。(按字母顺序排列模块是一个常见错误。例如:#2946)
要设置“Cache-Control”和“Expires”缓存响应头,请优先使用 mod_expire 而非 mod_setenv。
要设置“Content-Encoding”,请优先使用 mod_deflate。
另外:如果下面的 mod_setenv
配置选项不够灵活,可以使用 mod_magnet 实现任意复杂的头操作(例如 lua mod_setenv)。
要使用 mod_setenv:server.modules += ( "mod_setenv" )
选项¶
setenv.add-response-header
向发送给客户端的 HTTP 响应添加一个头
setenv.add-response-header = ("My-Custom-Header" => "my-custom-value")
setenv.add-request-header
向从客户端收到的 HTTP 请求添加一个头
setenv.add-request-header = ("X-Proxy" => "my.server.name")
setenv.add-environment
向传递给外部应用程序的进程环境(也称为环境变量)添加一个值
setenv.add-environment = ( "TRAC_ENV" => "lighttpd", "RAILS_ENV" => "production" )
setenv.set-request-header (自 1.4.46 起)
setenv.set-response-header (自 1.4.46 起)
setenv.set-environment (自 1.4.46 起)
这些指令设置给定值,而不是将给定值附加到头或环境中。这些指令优先于 setenv.add-* 对应指令。设置一个空值以移除请求头或移除响应头。
HTTP 严格传输安全 (HSTS)¶
典型的 HSTS 配置将 max-age 设置为 365 天(31536000 秒)。如果正在测试,请使用较短的 max-age(例如 max-age=600
),直到您对配置更有信心。除非您了解其后果,否则不要将 ; preload
附加到头值。
setenv.set-response-header += ("Strict-Transport-Security" => "max-age=31536000; includeSubDomains")
另请参阅下文的在多个配置条件下使用 setenv,了解如何将 HSTS 与其他 setenv 指令一起设置。
选择退出 Google 的同类群组联合学习 (FLoC)¶
EFF 文章:Google 的 FLoC 是一个糟糕的主意
setenv.set-response-header += ( "Permissions-Policy" => "interest-cohort=()" )
在多个配置条件下使用 setenv¶
lighttpd 处理其配置语法的方式对某些人来说可能不直观,但结果必须是确定性的。lighttpd 在启动时解析其配置。lighttpd 不会合并来自多个匹配条件的列表。对于每个特定的配置指令,与客户端请求匹配并包含该特定指令的最后一个条件是用于该客户端请求中该特定指令的配置。setenv-add-response-header
和 setenv-set-response-header
是不同的配置指令。
例如:对 "/abc/def/ghi" 的请求将匹配所有三个条件,即使指令是 setenv-add-response-header
,也只有最后一个会用于该请求,添加响应头 "Custom-Header: value-C"
$HTTP["url"] =~ "^/" { setenv.add-response-header = ("Custom-Header" => "value-A") } $HTTP["url"] =~ "^/abc/" { setenv.add-response-header = ("Custom-Header" => "value-B") } $HTTP["url"] =~ "^/abc/def/" { setenv.add-response-header = ("Custom-Header" => "value-C") }
顺序很重要。您编写配置的顺序很重要。对于相同的 "/abc/def/ghi" 请求,但配置指令以不同的顺序排列时,同样,最后一个匹配条件将用于该请求,在这种情况下添加响应头 "Custom-Header: value-A"
$HTTP["url"] =~ "^/abc/def/" { setenv.add-response-header = ("Custom-Header" => "value-C") } $HTTP["url"] =~ "^/abc/" { setenv.add-response-header = ("Custom-Header" => "value-B") } $HTTP["url"] =~ "^/" { setenv.add-response-header = ("Custom-Header" => "value-A") }
+=
也是如此。+=
仅适用于当前范围、当前配置条件内的列表。+=
不会跨不同配置条件生效。对于相同的 "/abc/def/ghi" 请求,但配置指令如下所列时,同样,最后一个匹配条件将用于该请求,在这种情况下添加响应头 "Custom-Header1: value-C" 和 "Custom-Header2: value-C"
$HTTP["url"] =~ "^/" { setenv.add-response-header = ("Custom-Header1" => "value-A") setenv.add-response-header+= ("Custom-Header2" => "value-A") } $HTTP["url"] =~ "^/abc/" { setenv.add-response-header = ("Custom-Header1" => "value-B") setenv.add-response-header+= ("Custom-Header2" => "value-B") } $HTTP["url"] =~ "^/abc/def/" { setenv.add-response-header = ("Custom-Header1" => "value-C") setenv.add-response-header+= ("Custom-Header2" => "value-C") }
以下是将一组 setenv 策略头定义到一个变量中并重用该组的一种方法
var.response_header_policy = ( #"strict-transport-security" => "max-age=31536000; includeSubDomains", # preferred for sites to designate HSTS "strict-transport-security" => "max-age=300; includeSubDomains", # minimize damage for those who blindly cut-n-paste "content-security-policy" => "default-src https:", "x-frame-options" => "SAMEORIGIN", "x-content-type-options" => "nosniff", "x-xss-protection" => "0", # https://mdn.org.cn/en-US/docs/Web/HTTP/Headers/X-XSS-Protection "permissions-policy" => "interest-cohort=()" # opt-out of Google's FLoC ) $HTTP["url"] =~ "^/" { setenv.set-response-header = var.response_header_policy setenv.set-response-header+= ("custom-header" => "value-A") } $HTTP["url"] =~ "^/abc/" { setenv.set-response-header = var.response_header_policy setenv.set-response-header+= ("custom-header" => "value-B") } $HTTP["url"] =~ "^/abc/def/" { setenv.set-response-header = var.response_header_policy setenv.set-response-header+= ("custom-header" => "value-C") }
另一种方法是利用父条件中有限的 +=
列表合并。由于 lighttpd 在启动时(而非运行时)解析配置,因此这种与 +=
的合并仅限于从直接父条件继承,而不是跨相同嵌套级别的对等条件。此外,虽然可以将新条目(键)添加到列表中,但通过这种方法不能复制或覆盖从父条件继承的列表键。
setenv.set-response-header = ( #"strict-transport-security" => "max-age=31536000; includeSubDomains", # preferred for sites to designate HSTS "strict-transport-security" => "max-age=300; includeSubDomains", # minimize damage for those who blindly cut-n-paste "content-security-policy" => "default-src https:", "x-frame-options" => "SAMEORIGIN", "x-content-type-options" => "nosniff", "x-xss-protection" => "0", # https://mdn.org.cn/en-US/docs/Web/HTTP/Headers/X-XSS-Protection "permissions-policy" => "interest-cohort=()" # opt-out of Google's FLoC ) $HTTP["url"] =~ "^/" { setenv.set-response-header+= ("custom-header" => "value-A") } $HTTP["url"] =~ "^/abc/" { setenv.set-response-header+= ("custom-header" => "value-B") } $HTTP["url"] =~ "^/abc/def/" { setenv.set-response-header+= ("custom-header" => "value-C") }
一些策略响应头应在所有响应中发送,但有些则不必在所有响应中发送,例如图像、脚本、样式表等。省略它们可能会节省一些带宽。参考 Scott Helme 的文章:微优化乐趣多!
自动解压缩¶
如果您的磁盘上有很多用 gzip 压缩的文本文件,并且希望浏览器在检索时解压缩它们,您可以使用 setenv 注入 Content-Encoding 头,但除非所有客户端都支持 Accept-Encoding: gzip
,否则不应这样做。您应该改为优先使用 mod_deflate,并用压缩内容预填充 mod_deflate 缓存位置。
$HTTP["url"] =~ "(README|ChangeLog|\.txt)\.gz$" { setenv.set-response-header = ( "Content-Encoding" => "gzip") mimetype.assign = ("" => "text/plain" ) }
强制客户端下载¶
要告诉客户端下载文件而不是尝试显示响应,请设置 Content-Disposition
。
$HTTP["url"] =~ "\.(dcf|m4a|mp3|mp4|wma|wmv|ogg|zip)$" { setenv.set-response-header = ("Content-Disposition" => "attachment") }
要动态设置
Content-Disposition
头,例如带有特定的 filename=...
参数,请参见 lua 示例:https://redmine.lighttpd.ac.cn/boards/2/topics/3127一些 PHP 示例可以在以下评论区找到:https://php.ac.cn/manual/en/function.header.php