23

重新提出问题,因为

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

不幸的是,展示完整的问题堆栈会导致一个很长的问题,而且它是非常特定于Mason的。

首先,只有意见的部分:)

我使用 HTML::Mason 已经很久了,现在尝试使用 Mason2。PoetMason 是 CPAN 中最先进的框架。没有发现任何可比的东西,开箱即用的东西可以写得如此干净/但非常容易破解:)/网络应用程序,包括许多电池(日志记录、缓存、配置管理、基于原生 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

单击下载 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

当然,输入 (the path_info) 没有被解码,脚本使用 utf8 编码的八位字节而不是 perl 字符。

所以,告诉 perl -“源代码在 utf8 中”,通过use utf8;<%class%>

+--------------------------+
| �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%>or<%perl%>块中的编码。在许多地方的 perl 代码中进行编码/解码(阅读不在边界处)会导致代码冗长。

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


部分解决。

令人高兴的是,诗人巧妙地允许修改它(和梅森)的部分,因此, $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。

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

主要问题是: - 在哪里(Moose 的方法修饰符应该修改哪些方法)以及如何正确解码输入以及输出在哪里(在 Poet/Mason 应用程序中。)

  • 但只有文本的,例如text/plainortext/html等​​等……
  • a 做上述“无惊喜” - 例如,什么会简单有效。;)

有人可以帮忙提供真正的代码吗 - 我应该在上面修改什么?

4

3 回答 3

4

Mason2 手册介绍了组件继承的工作方式,因此我认为将此通用代码放在您的Base.mp 组件中(所有其他组件都从中继承)可能会解决您的问题。

Mason::Manual::Plugins中描述了创建插件。

因此,您可以构建自己的插件来修改Mason::Request并通过覆盖request_args()您可以返回 UTF-8 解码参数。

编辑:

关于 UTF-8 输出,您可以添加Apache 指令以确保 text/plain 和 text/HTML 输出始终被解释为 UTF-8 :

AddDefaultCharset utf-8
于 2011-05-20T05:11:03.013 回答
1

在 mason-users 邮件列表中有一个关于处理 UTF-8 的问题

  1. 使用 UTF-8 输出的组件
  2. 处理 UTF-8 GET/POST 参数

这是乔恩的回答:

我希望 Mason 能够智能地处理编码,但由于我不经常使用 utf8,因此您和其他人将不得不帮助我进行设计。

这可能应该在插件中,例如 Mason::Plugin::UTF8。

因此,对于您特别提到的事情,这样的事情可能会起作用:

package Mason::Plugin::UTF8;
use Moose;
with 'Mason::Plugin';
1;

package Mason::Plugin::UTF8::Request;
use Mason::PluginRole;
use Encode;

# Encode all output in utf8 - ** only works with Mason 2.13 and beyond **
#
after 'process_output' => sub {
    my ($self, $outref) = @_;
    $$outref = encode_utf8( $$outref );
};

# Decode all parameters as utf8
#
around 'run' => sub {
    my $orig = shift;
    my $self = shift;

    my %params = @_;
    while (my ($key, $value) = each(%params)) {
        $value = decode_utf8($value);
    }
    $self->$orig(%params);
}

1;

如果您或其他了解 utf8 问题的人而不是我自己创建了这个插件,那可能是最好的。但是让我知道 Mason 核心中是否需要一些东西来使这更容易。

恕我直言,还需要添加以下内容,以添加“use utf8;” 进入每个组件。

package Mason::Plugin::UTF8::Compilation;
use Mason::PluginRole;
override 'output_class_header' => sub {
    return(super() . 'use utf8;');
};

1;
于 2011-07-24T14:32:29.403 回答
1

好的,我已经用 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;
于 2015-05-21T05:02:20.367 回答