Perl Catalyst - 从AJAX POST请求中获取JSON数据

时间:2013-12-03 22:11:13

标签: jquery ajax json perl catalyst

我正在尝试获取在Catalyst应用程序的homescreen页面上单击按钮时通过AJAX POST发送到服务器的JSON数据:

将JSON数据发送到服务器的AJAX POST:

$("#saveCanvasStates").click(function () {
// button to save canvas states to a database

// Serialize the states array
var JsonStringForTransport = JSON.stringify({stateForUserNumber7: states});

// POST the JSON to the server
var thePost = $.ajax({
    url: 'homescreen',
    type: 'POST',
    dataType: 'json',
    data: JsonStringForTransport,
    contentType: 'application/json; charset=utf-8'
});

我还有homescreen页面的以下Catalyst Controller,发送AJAX POST的按钮位于:

Catalyst Controller:

package MyProject::Controller::Homescreen;

use strict;
use warnings;
use parent 'Catalyst::Controller';
use Data::Dumper;

__PACKAGE__->config->{namespace} = '';

sub homescreen :Path('/homescreen') :Args(0)  {

        my ( $self, $c ) = @_;

        $c->stash({title => 'Home Screen',
                   pagetype => 'html',
                   template => 'homescreen.html'
                 });


#here is where I think I need to obtain the JSON data from the AJAX POST request 
#and save it to my database

}

1;

一旦我将这个JSON数据放在一个可以使用的表单中,我将把它保存到Postgres数据库。

从查看Catalyst::Request的CPAN文档,因为我的理解是这是在处理请求时引用的内容,可以使用以下内容来处理AJAX POST数据?:

  • $ C-> $ req-> body_data
  • $ C-> $ req-> body_parameters
  • $ C-> $ req-> body_params

但我不确定将数据转换为表格的最佳方法,然后我可以将其插入到我的数据库中,并且应该优先使用哪种方法?

非常感谢您对此的帮助,因为我能找到很少帮助我的文档,非常感谢。

-----更新----- (与RET的答案有关)

我肯定要显示body_data,因为当我这样做时:

print Dumper($c->req->body_data);

我在开发服务器日志中打印了以下内容:

$VAR1 = {
          'stateForUserNumber7' => [
                                     {
                                       'width' => 102,
                                       'offsetY' => 56,
                                       'x' => 11,
                                       'height' => 102,
                                       'image' => {},
                                       'y' => 14,
                                       'contextIndex' => 2,
                                       'dragging' => bless( do{\(my $o = 0)}, 'Cpanel::JSON::XS::Boolean' ),
                                       'offsetX' => 73
                                     },
                                     {
                                       'width' => 102,
                                       'offsetY' => 34,
                                       'x' => 103,
                                       'height' => 102,
                                       'image' => {},
                                       'y' => 17,
                                       'contextIndex' => 3,
                                       'dragging' => $VAR1->{'stateForUserNumber7'}[0]{'dragging'},
                                       'offsetX' => 46
                                     }
                                   ]
        };
[info] *** Request 15 (1.250/s) [17427] [Fri Dec  6 00:02:22 2013] ***
[debug] Path is "homescreen"
[debug] "POST" request for "homescreen" from "192.168.1.100"
[debug] Rendering template "homescreen.html"
[debug] Response Code: 200; Content-Type: text/html; charset=utf-8; Content-Length: 7010
[info] Request took 0.025343s (39.459/s)
.------------------------------------------------------------+-----------.
| Action                                                     | Time      |
+------------------------------------------------------------+-----------+
| /homescreen                                                | 0.014044s |
| /end                                                       | 0.001992s |
|  -> Organiser::View::TT->process                           | 0.001058s |
'------------------------------------------------------------+-----------'

-----进一步更新-----

这是使用-d

时在开发服务器输出中给出的错误
Caught exception in Organiser::Controller::Homescreen->homescreen "Can't use an undefined value as a HASH reference at /home/fred/Organiser/script/../lib/Organiser/Controller/Homescreen.pm line 21."

这是我在运行开发服务器时从Stack Trace获得的错误

Stack Trace
Package                             Line    File
Organiser::Controller::Homescreen   21    /home/fred/Organiser/lib/Organiser/Controller/Homescreen.pm

18: 
19: print STDERR Dumper $c->req->body_data; 
20: 
21: foreach my $data (@{$c->req->body_data->{stateForUserNumber7}}) {     <-- it highlights in bold this line
22:      print "DOLLAR DATA $data\n"; 
23: } 
24:

Organiser::Controller::Root     17  /home/fred/Organiser/lib/Organiser/Controller/Root.pm

14: sub index :Path :Args(0) { 
15: my ( $self, $c ) = @_; 
16: 
17: $c->forward('homescreen');       <-- it highlights in bold this line
18: 
19: } 
20: 

使用Firebug这是发生的POST请求(在我将foreach注释为错误之后)

Source
{"stateForUserNumber7":[{"dragging":false,"contextIndex":4,"image":{},"x":108,"y":4,"width":102,"height":102,"offsetX":45,"offsetY":65}]}

总是stateForUserNumber7(我应该将它命名为master_user或者其他东西)

3 个答案:

答案 0 :(得分:4)

虽然内置日志记录功能非常棒,但是当你让日志持续存在并进行分析时,我发现它并不是非常适合用于基本调试。我最近一直在使用Devel :: Dwarn这是一个简单的安装。这就像一个警告的翻斗车+非常整齐地卷起来。

如果你这样启动你的应用程序

perl -MDevel::Dwarn ...

你可以坚持Dwarn $ref并获得一个不错的stderr输出:

Dwarn $c->req->body_data

应该给你一个整洁的评论。另外,如果你放弃-MDevel::Dwarn,你会在你不小心离开Dwarn的所有地方出现错误(我上个月应该对已经发布的Runner 002版本做了些什么)。

如果这让您感到困惑,请尝试:

(在cpanm Devel::Dwarn之后)

use Devel::Dwarn;
Dwarn $c->req->body_data

您应该在控制台上获得深层结构输出。祝你好运!

答案 1 :(得分:2)

对于调试Catalyst / JSON问题的任何人,我的另一个答案是(希望是)有用的信息。但是对问题的后续更新表明这里的问题实际上是完全不同的。

此处没有足够的操作来支持所需的功能。如果index操作转发到呈现homescreen模板的homescreen.html操作,那么$.json()调用必须是其他一些负责处理数据保存的操作请求,别无其他

package MyProject::Controller::Homescreen;

use strict;
use warnings;
use parent 'Catalyst::Controller';
use JSON;

sub homescreen :Path('/homescreen') :Args(0)  {

    my ( $self, $c ) = @_;
    $c->stash({title => 'Home Screen',
               pagetype => 'html',
               template => 'homescreen.html'
    });
}

sub savecanvasstates :Local {
    my ($self, $c, @args) = @_;
    my $p = $c->req->param->{stateForUserNumber7} || die "wrong parameters!";
    my $result = {};
    foreach my $r (@{$p}) {
        # ... do something with $r->{x} etc
        $result->{output} = # construct whatever object the ajax caller expects
    }
    $c->res->body(to_json($result))
}

1;

在附近的一些JavaScript中:

$("#saveCanvasStates").click(function () {
    // button to save canvas states to a database

    // Serialize the states array
    var JsonStringForTransport = JSON.stringify({stateForUserNumber7: states});

    // POST the JSON to the server
    var thePost = $.ajax({
        url: 'savecanvasstates',
        type: 'POST',
        dataType: 'json',
        data: JsonStringForTransport,
        contentType: 'application/json; charset=utf-8',
        success: function(data, textStatus){ ... }
        error: function(XMLHttpRequest, textStatus, errorThrown){ ... }
    });
});

我希望所有这一切能让你做得更清楚。

答案 2 :(得分:1)

您的Catalyst应用不会收到JSON。 dataType参数告诉$.ajax()如何解析从服务器返回的数据。发送到服务器的是带有HTML表单参数的沼泽标准GET或POST请求。

当Catalyst收到它们时,它们是$c->req->params内的普通旧密钥,非常适合您想要启动的任何数据库操作。

所以,如果

/* JS */
JsonStringForTransport = { foo: "bar", baz: "quux" };

然后在Catalyst端,您将收到:

# perl
my $foo = $c->req->params->{foo}; # or $c->req->body_params->{foo}
if ($c->req->params->{baz} eq "quux"){ ... }

......等等。


<强>更新

所以body_data包含一个哈希(不出所料),它有一个键stateForUserNumber7,它包含对哈希数组的引用。这就是Dumper输出告诉你的。

您应该可以使用以下内容访问body_data

my $first_x = $c->req->body_data->{stateForUserNumber7}->[0]->{x};
print STDERR "first_x = $first_x\n"; # should print first_x = 11

但是,你更有可能想做类似的事情:

foreach my $data (@{$c->req->body_data->{stateForUserNumber7}}) {
    # do something with $data->{x}, $data->{y}, $data->{height} etc
}

<强>更新

jnap 发表了一篇关于如何在2013 Catalyst Advent Calendar中使用body_data的非常好的文章。如果您在应用中使用此功能而不是更传统的params,那么您一定要花时间阅读并吸收它。


<强>更新

很抱歉,早些时候对dataType提出了错误的解答,所以我已经纠正了这一点。但它并没有改变我答案的基本原理。

我认为你必须反省你的body_data来弄清楚出了什么问题。它总是'stateForUserNumber7',还是因请求而异?什么

$c->log->debug("body_params keys: " _ join(", ", keys %{ $c->req->body_data }));

产生

您必须使用开发服务器(即bin/myapp_server.pl),以便获得完整的调试输出以帮助您。建议不要通过Apache或FastCGI进行调试。