如何让 Mojolicious 处理 UTF-8?

x-y*_*uri 5 unicode perl utf-8

考虑以下代码。这样我就得到了一个文件的“syswrite 中的宽字符”,并在浏览器中得到了垃圾:

use Mojolicious::Lite;
use Mojo::UserAgent;
use Mojo::File;

get '/' => sub {
    my $c = shift;
    my $ua  = Mojo::UserAgent->new;
    $res = $ua->get('https://...')->result;
    Mojo::File->new('resp')->spurt($res->dom->at('.some-selector')->text);
    $c->render(text => $res->body);
}

app->start;
Run Code Online (Sandbox Code Playgroud)

但它是这样工作的:

use Encode qw/encode_utf8 decode_utf8/;
Mojo::File->new('resp')->spurt(encode_utf8($res->dom->at('.some-selector')->text));
Mojo::File->new('resp')->spurt($res->body);
$c->render(text => decode_utf8($res->body));
Run Code Online (Sandbox Code Playgroud)

你能解释一下这里发生了什么吗?为什么这两个语句在没有Encode模块的情况下不起作用?为什么第二个有效?有没有更好的处理方法?我已经浏览了perluniintroperlunicode,但这是我所能得到的。

x-y*_*uri 5

我从perluniintroperlunicode和 xxfelixxx 的链接中了解到,Unicode 是一个复杂的问题。你通常不能让它正常工作。有字节(八位字节)和文本。在处理输入之前,您大部分时间必须将字节转换为文本 ( decode),而在输出之前,您必须执行相反的操作 ( encode)。如果不是关于第三方库,可以做use open qw( :encoding(UTF-8) :std );, 或binmode. 但是对于第三方库,您并不总是能够这样做。

因此,$res->body是字节,$res->text是从响应中指定的编码解码的文本。$res->dom需要$res->text作为输入。所以,$res->dom->at('.some-selector')->text是文本,并Mojo::File->new(...)->spurt()期望得到字节。所以你别无选择,只能使用 UTF-8 对其进行编码。顺便说一句,utf8不是UTF-8。后者更安全,所以最好使用encode/decode函数。

然后,$c->render(text => ...);期望文本,而不是字节。所以你要么必须通过decode('UTF-8', $res->body),要么通过$res->text