在 lighttpd 中使用 Mason (通过 FastCGI)¶
Mason 可以与 Lighttpd 配合使用,并且(可以说 :-) 比 Apache + mod_perl 更容易设置。
这是我当前的设置。要求
- Mason 处理以 '/'、'.html' 或 '.css' 结尾的文件。
- 其他文件由 lighttpd 静态提供服务
- 在 fastcgi 进程启动时加载 perl 模块
- 禁止访问 .mhtml 文件
首先,我们需要一个 Mason 处理器,lighttpd 将通过 FastCGI 使用它。我将其命名为 mason_lighttpd_handler.fcgi。它不需要放在任何特定位置。
#!perl #!/usr/bin/perl use CGI::Fast; use HTML::Mason::CGIHandler; use URI; { package HTML::Mason::Commands; ## anything you want available to components use Storable qw(freeze thaw); use HTTP::BrowserDetect; ## An example of how to keep a $dbh persistent ##our $dbh = DBI->connect_cached( ## 'dbi:Pg:dbname=dbname' ## , 'username' ## , 'password' ## , {AutoCommit=>0, RaiseError=>1, PrintError=>1} ##) || die "Could not Connect to DB".$dbi::errstr ; } # lazily-instantiated variables my $cgi; my $h; while ($cgi = new CGI::Fast()) { ## make sure it is alive! (if not it will reconnect) ## $HTML::Mason::Commands::dbh->ping; my $uri = URI->new( $ENV{REQUEST_URI} ); ## this is a hack, that emulates mod_perl behavior see notes at bottom ## You might not want this hack, and it might be worse than not having it $uri->path( $uri->path . 'index.html' ) if $uri->path =~ /\/$/ ; $ENV{PATH_INFO} = $uri->path; $ENV{QUERY_STRING} = $uri->query; $ENV{REQUEST_URI} = "$uri"; # this is lazily instantiated because %ENV is not set at startup time if (! $h) { $h = HTML::Mason::CGIHandler->new( comp_root => $ENV{MASON_COMP_ROOT} , data_dir => $ENV{MASON_DATA_ROOT} , error_mode => 'fatal' , error_format => 'line' ## Three good globals dbh user and session , allow_globals => [qw/$dbh $U $S/] ); } ## hand off to mason eval { $h->handle_cgi_object($cgi) }; ## catch error if ( my $raw_error = $@ ) { $HTML::Mason::Commands::dbh->rollback; ## roll back warn $raw_error; # print out a pretty system error page and log $raw_error } ## things went well else { $HTML::Mason::Commands::dbh->commit; } } exit 0;
接下来,我们需要告诉 Lighttpd 处理此站点的请求,并通过此脚本和 FastCGI 进行处理。这是相关的片段。我正在使用正则表达式来表示主机名表达式
但你可能需要更简单的东西——更多信息请参阅 Lighttpd 文档
#!python $HTTP["host"] =~ "hostnameexpression" { server.document-root = "/path/to/your/document/root" ## map .css and '/' to .html so they will be handled by FastCGI fastcgi.map-extensions = ( ".css" => ".html", "/" => ".html" ) index-file.names = ( "index.html" ) url.access-deny = ( ".mhtml" ) ## add autohandler/dhandler if you'd like fastcgi.server = ( ".html" => (( "socket" => "/tmp/fastcgi.socket", "bin-path" => "/path/to/the/mason_lighttpd_handler.fcgi", "check-local" => "disable" )) ) bin-environment = ( MASON_COMP_ROOT => '/your/comp/root', MASON_DATA_ROOT => '/your/data/root' ) }
就是这样!
当你启动 lighttpd 时,它将启动你的 Mason 处理器脚本的多个副本,并根据需要将请求传递给它们。
这样做的一个好处是,如果你更改了一个 perl 模块(而不是 Mason 组件),这在 Apache mod_perl 服务器中需要重启/重新加载,而在这种情况下,你只需终止 perl fastcgi 进程——lighttpd 会发现并重新启动它们,当然会加载你的新模块代码。
如果你得到意外结果,请在你的处理器脚本中添加调试(通过 'warn'),你可以在 lighttpd 错误日志中看到其输出。
已知问题¶
$m->abort 无法正常工作,有关原因的详细信息请参阅此页面
http://www.masonhq.com/docs/manual/1.28/CGIHandler.html#calling_abort___under_cgihandler
看来这是需要在 Mason 中修复的问题。
从 Apache/mod_* (mod_perl) 迁移¶
首先是前言,mod_*(语言)将语言的 .so 文件嵌入到 Apache 中。这样做,它知道 FastCGI 不知道的事情,并且可以做 FastCGI 不能做的事情。用户可能在不知情的情况下利用了其中一些行为,这里有一个很好的例子
在 Apache 中,(mod_* 而非 FastCGI)对 '/' 的请求将由以下方式处理:
- 首先查找 DirectoryIndex(Apache 会完成此操作。)
- 使用找到的 DirectoryIndex 调用包装器;或者,在未找到的文件上调用包装器(这将调用 dhandler)。
在 Lighttpd 中,或者通常在 CGI 中,缺少对索引文件的解析,因此包装器可能会在请求的文件上被调用,也可能不会。请参阅 lighttpd 中的 "check-local" 指令。在 CGI 中,索引文件(Apache 的 DirectoryIndex)没有影响。相比之下,Lighttpd/FastCGI 看起来像这样
- 使用找到的文件调用包装器;或者,如果禁用 check-local,则使用未找到的文件调用包装器。
一个糟糕的解决方案是将所有目录重定向到该目录的 index.html。一个不那么糟糕的解决方案是在包装器中编写转换过程(这仅在禁用 check-local 时有效)。
另一个问题——对前面提到的问题的扩展是,一个没有路径,只有查询字符串的地址。例如
http://foo.com/?test.html 或 /?test.html,或 /bar/?test.html
在 Apache 中,解析看起来像这样
- 首先查找 DirectoryIndex(Apache 会完成此操作。)
- 使用找到的 DirectoryIndex 调用包装器;带上查询。
在 Lighttpd 中(即 CGI),情况并非如此。总结:如果你将所有内容发送到包装器(不检查文件是否存在),索引文件就无关紧要。如果你的应用程序使用了 Apache 的解析,这可能会带来麻烦。如果你不将所有内容发送到包装器,你将完全失去 dhandler 功能。
UTF-8 支持¶
如果你的 Mason 页面使用 UTF-8 编码编写,那么 lighttpd 可能会以错误的编码显示它们。要将所有页面视为 UTF8,请像这样更改 CGIHandler 调用
$h = HTML::Mason::CGIHandler->new( comp_root => $ENV{MASON_COMP_ROOT} , data_dir => $ENV{MASON_DATA_ROOT} , error_mode => 'fatal' , error_format => 'line' , preamble => 'use utf8;' ## Three good globals dbh user and session , allow_globals => [qw/$dbh $U $S/] );
如果你使用 MySQL,最好也将数据库记录作为 UTF8 字符串拉取。数据库部分应该看起来像这样
our $dbh = DBI->connect_cached($dsn, 'username', 'password', {mysql_enable_utf8 => 1, AutoCommit => 1, RaiseError => 1 , PrintError => 1}) || die "Could not Connect to DB".$dbi::errstr ;
鸣谢¶
最新重写 (Evan Carroll <me@evancarroll.com>)
- 为 comp/data 根目录添加了环境变量
- 添加了 DBI 与 fastcgi 持久化的示例
- 移除了原始的查询解析正则表达式,转而使用 URI。
- 添加了一些要共享的全局变量
(Justin Hawkins <justin@hawkins.id.au>) 初稿。
在这个阶段,这非常属于“似乎有效”的范畴。(最初的备注仍然适用)
由 eryretqwewrqr 大约 13 年前 更新 · 20 次修订