Perl Mojolicious,从 Promise 中呈现响应的正确方法是什么?

问题描述 投票:0回答:1

在 Mojolicious 中,渲染 Promise 响应的正确方法是什么?在我下面的代码中,我得到:

[2023-04-12] [trace] Template "example/search.html.ep" not found
[2023-04-12] [trace] Nothing has been rendered, expecting delayed response
  1. 它为什么要找
    example/search.html.ep
    ?我没有要求它。
  2. 我正在渲染内容……Mojo 等不及了?

我的示例应用程序有 3 个文件:

1。
script/my_app

#!/usr/bin/env perl

use strict;
use warnings;

use Mojo::File qw(curfile);
use lib curfile->dirname->sibling('lib')->to_string;
use Mojolicious::Commands;

Mojolicious::Commands->start_app('MyApp');

2。
lib/MyApp.pm

package MyApp;
use Mojo::Base 'Mojolicious', -signatures;

sub startup ($self) {
    $self->secrets('s3cret');
    my $r = $self->routes;
    $r->get('/')->to('Example#index');
    $r->post('/')->to('Example#search');
}

1;

3。
lib/MyApp/Controller/Example.pm

package MyApp::Controller::Example;
use Mojo::Base 'Mojolicious::Controller', -signatures;

sub index ($self)
{
    return $self->render(inline => '<html><body><form method="post"><textarea name="numbers" maxlength="11">123</textarea><button type="submit">Go</button></form></body></html>');
}

sub search ($self)
{
    my $v = $self->validation;
    $v->required("numbers");
    return $self->render(text=>"Validation Error") if $v->has_error;
    my $numbers = $v->param("numbers");
    my @numbers = split(/\r?\n/, $numbers);

    Mojo::Promise
    ->map(
    {concurrency => 2},
    sub {
        $self->ua->get_p("https://httpbin.org/delay/1?q=$_" => {'api-key'=>'shhh'});
    }, @numbers)
    ->then(
    sub{
        my @results = @_;
        my @json = map { $_->[0]->res->json } @results;
        return $self->render(json => \@json);
    })
    ->catch(
    sub {
        my $err = shift;
        return $self->render(text => $err);
    })
    ->wait;
    #return $self->render(text => "This shall result is 'Unhandled rejected promise: A response has already been rendered'");
}

1;

要运行应用程序,我这样做:

morbo script/my_app

然后导航到

http://localhost:3000
并发布表格。多行将导致并发调用。

rest perl promise concurrency mojolicious
1个回答
1
投票

在调用 Promise 之前添加一个

render_later

$self->render_later();

Mojo::Promise
  ->map(
    {concurrency => 2},
...

没有它,当函数

search
退出时,Mojolicious将默认渲染关联的模板(
example/search.html.ep
),并失败,因为该模板不存在(参见Mojolicious::Guide::Rendering中的Automatic rendering) .
render_later
禁用此自动渲染,基本上告诉 Mojolicious “保持连接打开,我稍后会渲染一些东西”。


您的困惑可能来自于使用

wait
,在这种情况下它并不是真正的“等待”。如果你在整个承诺之前和之后添加打印:

say "Before";
Mojo::Promise->map(...);
say "After";

那么日志会是:

[2023-04-13 09:23:08.78601] [1201283] [trace] [rR7TxcCsrygT] POST "/"
[2023-04-13 09:23:08.78692] [1201283] [trace] [rR7TxcCsrygT] Routing to controller "MyApp::Controller::Example" and action "search"
Before
After
[2023-04-13 09:23:08.78953] [1201283] [trace] [rR7TxcCsrygT] Template "example/search.html.ep" not found
...

这确实表明

wait
并没有真正等待(如果您不相信,您甚至可以在
then
catch
中添加打印:它们将在
Before
之后打印)。

看着wait

documentation
,它说:

启动“ioloop”并在承诺完成或拒绝后再次停止它,当“ioloop”已经运行时什么都不做。

在这里,由于您正在运行服务器,因此 IOLoop 始终在运行,因此

wait
什么都不做。这实际上是可取的:如果
wait
真的要等待,那么使用 Promise 就没有意义了。
另一方面,当您单独使用 Mojo::Promise(即,不在 Mojolicious 服务器中)时,您可能需要使用
wait
手动运行 IOLoop,以便在您的承诺完成之前不退出您的脚本。

© www.soinside.com 2019 - 2024. All rights reserved.