重新表述问题,因为
- @optional ask me
- 它不清楚,并链接一个基于HTML::Mason的解决方案四个简单的步骤使Mason UTF-8 Unicode干净与Apache, mod_perl,和DBI,是什么造成的混乱
- 原作已有4年历史,同时(2012年)创作了"诗人"
评论:这个问题已经赢得了"热门问题徽章",所以我可能不是唯一一个没有希望的人。:)
不幸的是,演示完整的问题堆栈会导致一个非常长的问题,并且它非常特定于Mason。
首先是意见部分:)
我一直在使用HTML::Mason,现在尝试使用Mason2。诗人与泥瓦匠是CPAN中最先进的框架。没有发现任何可比性,什么开箱即用的允许编写如此干净/但非常可编程:)/web应用程序,包含许多电池(日志记录,缓存,配置管理,基于本地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
当然,输入(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%>
或<%perl%>
块中的编码。在perl代码的内的许多地方编码/解码, (read: not at the borders)会导致代码杂乱。
编码/解码应该在的某个地方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;
)
);
};
what将在每个 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/plain
或text/html
等。 - a做上面的"惊喜自由"-例如,什么会简单地工作。)
有人可以帮助真正的代码-我应该在上面修改什么?
Mason2手册介绍了组件继承的工作方式,所以我认为应该将这些通用代码放在main基中。Mp组件(所有其他组件都继承它)可能会解决您的问题。
创建插件的描述见Mason::Manual:: plugins 。
所以,你可以构建自己的插件来修改Mason::Request,通过重写request_args()
,你可以返回UTF-8解码的参数。
关于UTF-8输出,你可以添加一个Apache指令来确保text/plain和text/HTML输出总是被解释为UTF-8:
AddDefaultCharset utf-8
好的,我已经在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;
在mason-users邮件列表中有一个关于
处理UTF-8的问题- 组件输出UTF-8
- 处理UTF-8 GET/POST参数
下面是Jon的回答:
我希望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;