perl - 如何使Mason2 UTF-8干净?

标签 perl utf-8 moose mason plack

重新制定问题,因为

  • @可选asked me
  • 尚不清楚,并链接了一个基于HTML::Mason的解决方案Four easy steps to make Mason UTF-8 Unicode clean with Apache, mod_perl, and DBI ,是什么引起了困惑
  • 原来是4岁,并且在此期间(2012年)创建了“poet”

  • 评论:这个问题已经赢得了“热门问题徽章”,所以可能我不是唯一没有希望的人。 :)

    不幸的是,演示完整的问题堆栈会导致一个很长的问题,并且它是Mason特有的。

    首先,仅提供意见的部分:)

    我使用HTML::Mason已有很多年了,现在尝试使用Mason2。
    PoetMason
    是CPAN中最先进的框架。
    没发现什么可比性,开箱即用的东西可以写得很干净,但很容易被黑:)/ web-apps,
    包括许多电池(日志,缓存,配置管理,基于本地PGSI的等等)

    不幸的是,作者不在乎这个词的其余部分,
    例如默认情况下,它仅基于ascii,
    没有任何有关的手册,常见问题或建议:如何与unicode一起使用

    现在的事实。演示创建一个诗人应用程序:
    poet new my #the "my" directory is the $poet_root
    mkdir -p my/comps/xls
    cd my/comps/xls
    

    并在dhandler.mc中添加以下内容(将降低两个基本问题的程度)
    <%class>
        has 'dwl';
        use Excel::Writer::XLSX;
    </%class>
    <%init>
        my $file = $m->path_info;
    
        $file =~ s/[^\w\.]//g;
        my $cell = lc join ' ', "ÅNGSTRÖM", "in the", $file;
    
        if( $.dwl ) {
            #create xlsx in the memory
            my $excel;
            open my $fh, '>', \$excel or die "Failed open scalar: $!";
            my $workbook  = Excel::Writer::XLSX->new( $excel );
            my $worksheet = $workbook->add_worksheet();
            $worksheet->write(0, 0, $cell);
            $workbook->close();
    
            #poet/mason output
            $m->clear_buffer;
            $m->res->content_type("application/vnd.ms-excel");
            $m->print($excel);
            $m->abort();
        }
    </%init>
    <table border=1>
    <tr><td><% $cell %></td></tr>
    </table>
    <a href="?dwl=yes">download <% $file %></a>
    

    并运行该应用
    ../bin/run.pl
    

    转到http://0:5000/xls/hello.xlsx,您将获得:
    +----------------------------+
    | ÅngstrÖm in the hello.xlsx |
    +----------------------------+
    download hello.xlsx
    

    单击download hello.xlsx,您将在下载中获得hello.xlsx

    上面讲的第一个问题,
    例如组件的源代码不在use utf8;下,
    因此lc无法理解字符。

    第二个问题如下,尝试
    [http://0:5000/xls/hélló.xlsx],或
    http://0:5000/xls/h%C3%A9ll%C3%B3.xlsx
    您会看到:
    +--------------------------+
    | ÅngstrÖm in the hll.xlsx |
    +--------------------------+
    download hll.xlsx
    #note the wrong filename
    

    当然,输入(path_info)不会被解码,该脚本适用于utf8编码的八位字节,而不适用于perl字符。

    因此,通过将use utf8;添加到<%class%>中,告诉perl-“源位于utf8中”
    +--------------------------+
    | �ngstr�m in the hll.xlsx |
    +--------------------------+
    download hll.xlsx
    

    添加use feature 'unicode_strings'(或use 5.014;)更糟:
    +----------------------------+
    | �ngstr�m in the h�ll�.xlsx |
    +----------------------------+
    download h�ll�.xlsx
    

    当然,,源现在包含宽字符,在输出中需要Encode::encode_utf8

    可以尝试使用以下过滤器:
    <%filter uencode><% Encode::encode_utf8($yield->()) %></%filter>
    

    并过滤整个输出:
    % $.uencode {{
    <table border=1>
    <tr><td><% $cell %></td></tr>
    </table>
    <a href="?dwl=yes">download <% $file %></a>
    % }}
    

    但这只能部分帮助,因为需要注意<%init%><%perl%>块中的编码。
    在很多地方,在perl代码的内对进行编码/解码(阅读:不在边界处)会导致代码不稳定。

    编码/解码应清楚地在
    处的处完成。
    Poet / Mason边界-当然,Plack在字节级别运行。

    部分解决方案。

    高兴的是,Poet巧妙地允许修改其(和梅森的)零件,因此,
    $poet_root/lib/My/Mason中,您可以将Compilation.pm修改为:
    override 'output_class_header' => sub {
        return join("\n",
            super(), qq(
            use 5.014;
            use utf8;
            use Encode;
            )
        );
    };
    

    将每个 Mason组件插入所需的序言到中的内容。 (不要忘记触摸每个组件,或者只是从$poet_root/data/obj中删除已编译的对象)。

    您也可以尝试在边界处理请求/响应,
    通过将$poet_root/lib/My/Mason/Request.pm编辑为:
    #found this code somewhere on the net
    use Encode;
    override 'run' => sub {
        my($self, $path, $args) = @_;
    
        #decode values - but still missing the "keys" decode
        foreach my $k (keys %$args) {
            $args->set($k, decode_utf8($args->get($k)));
        }
    
        my $result = super();
    
        #encode the output - BUT THIS BREAKS the inline XLS
        $result->output( encode_utf8($result->output()) );
        return $result;
    };
    

    对所有内容进行编码是错误的策略,例如会破坏。 XLS。

    因此,四年后(我在2011年问了最初的问题)仍然不知道:(如何在Mason2应用程序中正确使用unicode,并且仍然不存在任何有关它的文档或帮助程序。:(

    主要问题是:
    -哪里(应该通过Moose的方法修改器修改哪些方法)以及如何正确解码输入和输出(在Poet / Mason应用中)。
  • ,但只能是文字的,例如text/plaintext/html等...
  • a执行上述“无意外”-例如什么将简单地工作。 ;)

  • 有人可以提供真实代码帮助吗-我应该在上面进行哪些修改?

    最佳答案

    好的,我已经用Firefox测试过了。 HTML会正确显示UTF-8,而不会保留zip,因此应可在任何地方使用。

    如果从poet new My开始应用补丁,则需要patch -p1 -i...path/to/thisfile.diff

    diff -ruN orig/my/comps/Base.mc new/my/comps/Base.mc
    --- orig/my/comps/Base.mc   2015-05-20 21:48:34.515625000 -0700
    +++ new/my/comps/Base.mc    2015-05-20 21:57:34.703125000 -0700
    @@ -2,9 +2,10 @@
     has 'title' => (default => 'My site');
     </%class>
    
    -<%augment wrap>
    -  <html>
    +<%augment wrap><!DOCTYPE html>
    +  <html lang="en-US">
         <head>
    +      <meta charset="utf-8">
           <link rel="stylesheet" href="/static/css/style.css">
     % $.Defer {{
           <title><% $.title %></title>
    diff -ruN orig/my/comps/xls/dhandler.mc new/my/comps/xls/dhandler.mc
    --- orig/my/comps/xls/dhandler.mc   1969-12-31 16:00:00.000000000 -0800
    +++ new/my/comps/xls/dhandler.mc    2015-05-20 21:53:42.796875000 -0700
    @@ -0,0 +1,30 @@
    +<%class>
    +    has 'dwl';
    +    use Excel::Writer::XLSX;
    +</%class>
    +<%init>
    +    my $file = $m->path_info;
    +    $file = decode_utf8( $file );
    +    $file =~ s/[^\w\.]//g;
    +    my $cell = lc join ' ', "ÅNGSTRÖM", "in the", $file ;
    +    if( $.dwl ) {
    +        #create xlsx in the memory
    +        my $excel;
    +        open my $fh, '>', \$excel or die "Failed open scalar: $!";
    +        my $workbook  = Excel::Writer::XLSX->new( $fh );
    +        my $worksheet = $workbook->add_worksheet();
    +        $worksheet->write(0, 0, $cell);
    +        $workbook->close();
    +
    +        #poet/mason output
    +        $m->clear_buffer;
    +        $m->res->content_type("application/vnd.ms-excel");
    +        $m->print($excel);
    +        $m->abort();
    +    }
    +</%init>
    +<table border=1>
    +<tr><td><% $cell %></td></tr>
    +</table>
    +<p> <a href="%c3%85%4e%47%53%54%52%c3%96%4d%20%68%c3%a9%6c%6c%c3%b3">ÅNGSTRÖM hélló</a>
    +<p> <a href="?dwl=yes">download <% $file %></a>
    diff -ruN orig/my/lib/My/Mason/Compilation.pm new/my/lib/My/Mason/Compilation.pm
    --- orig/my/lib/My/Mason/Compilation.pm 2015-05-20 21:48:34.937500000 -0700
    +++ new/my/lib/My/Mason/Compilation.pm  2015-05-20 21:49:54.515625000 -0700
    @@ -5,11 +5,13 @@
     extends 'Mason::Compilation';
    
     # Add customizations to Mason::Compilation here.
    -#
    -# e.g. Add Perl code to the top of every compiled component
    -#
    -# override 'output_class_header' => sub {
    -#      return join("\n", super(), 'use Foo;', 'use Bar qw(baz);');
    -# };
    -
    +override 'output_class_header' => sub {
    +    return join("\n",
    +        super(), qq(
    +        use 5.014;
    +        use utf8;
    +        use Encode;
    +        )
    +    );
    +};
     1;
    \ No newline at end of file
    diff -ruN orig/my/lib/My/Mason/Request.pm new/my/lib/My/Mason/Request.pm
    --- orig/my/lib/My/Mason/Request.pm 2015-05-20 21:48:34.968750000 -0700
    +++ new/my/lib/My/Mason/Request.pm  2015-05-20 21:55:03.093750000 -0700
    @@ -4,20 +4,27 @@
    
     extends 'Mason::Request';
    
    -# Add customizations to Mason::Request here.
    -#
    -# e.g. Perform tasks before and after each Mason request
    -#
    -# override 'run' => sub {
    -#     my $self = shift;
    -#
    -#     do_tasks_before_request();
    -#
    -#     my $result = super();
    -#
    -#     do_tasks_after_request();
    -#
    -#     return $result;
    -# };
    +use Encode qw/ encode_utf8 decode_utf8 /;
    
    -1;
    \ No newline at end of file
    +override 'run' => sub {
    +    my($self, $path, $args) = @_;
    +    foreach my $k (keys %$args) {
    +        my $v = $args->get($k);
    +        $v=decode_utf8($v);
    +        $args->set($k, $v);
    +    }
    +    my $result = super();
    +    my( $ctype, $charset ) = $self->res->headers->content_type_charset;
    +    if( ! $ctype ){
    +        $ctype = 'text/html';
    +        $charset = 'UTF-8';
    +        $self->res->content_type( "$ctype; $charset");
    +        $result->output( encode_utf8(''.( $result->output())) );
    +    } elsif( ! $charset and $ctype =~ m{text/(?:plain|html)} ){
    +        $charset = 'UTF-8';
    +        $self->res->content_type( "$ctype; $charset");
    +        $result->output( encode_utf8(''.( $result->output())) );
    +    }
    +    return $result;
    +};
    +1;
    

    关于perl - 如何使Mason2 UTF-8干净?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5858596/

    相关文章:

    perl - 在 Perl 中声明变量

    macos - 在 Big Sur 上使用 perlbrew 安装 perl 时出错

    unicode - 如何将 UNICODE 希伯来语在 VBScript 中显示为乱码?

    html - 如果 HTML5 的默认字符编码是 UTF-8,为什么需要在 HTML5 文档中指定字符编码?

    子类中的 perl moose 触发器破坏方法修饰符

    perl - 模棱两可的调用解析为 CORE::join(),限定为这样或使用 & at

    python - 为什么 string.encode ('utf-8' ) != bytes(map(ord, string)) 是真的?

    perl - 这是 Moose Perl 的一个很好的替代品吗?

    perl - 将 CatalystX::I18N::Maketext 添加到我的 DBIC 架构中

    perl - 我可以使用数组的大小而不必将它放在变量中吗