项目

通用

个人资料

操作

在 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 <>)
- 为 comp/data 根目录添加了环境变量
- 添加了 DBI 与 fastcgi 持久化的示例
- 移除了原始的查询解析正则表达式,转而使用 URI。
- 添加了一些要共享的全局变量

(Justin Hawkins <>) 初稿。

在这个阶段,这非常属于“似乎有效”的范畴。(最初的备注仍然适用)

eryretqwewrqr 大约 13 年前 更新 · 20 次修订