2018-01-11
Furl で配列のパラメータを渡す
Furl で、配列のパラメータを渡すの(hoge=aaa&hoge=bbb
みたいなやつ)をやろうとしたら、うまく行かなかったのでメモ。
app.psgi
まず確認用の psgi を作ります。パラメータ hoge
の値を返すだけの物体です。
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use Plack::Request;
my $app = sub {
my $env = shift;
my $req = Plack::Request->new($env);
my @params = $req->parameters->get_all('hoge');
return [
200,
[ "Content-Type", "text/plain" ],
[ Dumper(\@params) ],
];
};
test.pl (ダメ版)
普通にパラメータをハッシュリファレンスで渡すやり方です。Furl がいい感じに POST リクエストのパラメータに変換してくれることを期待しています。(値が配列でなければ問題なく動く)
#!/usr/bin/perl
use strict;
use warnings;
use Furl;
use URI;
my $param = { hoge => ['aaa', 'bbb'] };
my $ua = Furl->new();
my $header = [
'CONTENT-TYPE' => 'application/x-www-form-urlencoded',
];
my $res = $ua->post('http://localhost:5000', $header, $param);
warn $res->content;
さっきの PSGI アプリを動かした上で、実行するとこうなります。
perl test.pl
$VAR1 = [
'ARRAY(0x7ffcb8803268)'
];
なんかおかしなもの(配列リファレンスじゃなくて、なぜかそのアドレスの文字列)が返って来ます。。。
$param = { hoge => 'aaa' }
みたいな値の場合は
$VAR1 = [
'aaa'
];
となるので、大丈夫なんですけどね。困ったものです。
test.pl (大丈夫だった版)
「これはこれでどうなんだ」感はありますが、自前で URI モジュールでパラメータを作ってあげるとうまく動くようです。
#!/usr/bin/perl
use strict;
use warnings;
use Furl;
use URI;
my $param = { hoge => ['aaa', 'bbb'] };
my $ua = Furl->new();
my $uri = URI->new();
$uri->query_form($param);
my $header = [
'CONTENT-TYPE' => 'application/x-www-form-urlencoded',
];
my $res = $ua->post('http://localhost:5000', $header, $uri->query);
warn $res->content;
実行すると、こんな感じ。
$VAR1 = [
'aaa',
'bbb'
];
期待した通り、配列で値を渡すことができるようになっています。
あんまり深く追いかけていないのですが、LWP::UserAgent でもダメっぽいし、そもそもWebアプリとしては配列でパラメータを受けるのはだいぶ微妙(セキュリティーホールにならないように、Plack::Request はだいぶ面倒というか、あえて面倒にして Hash::MultiValue で受けないとダメにしているくらい)なので、あまり使っている人がいないのかもしれない。
あと、比較的モジュールが新しい環境で試してはいるのだけど、もしかすると周辺のモジュール(HTTP::Request とか HTTP::Message とかその辺)のバージョンを上げると治ってしまったりするのかもしれない。っていうかこの現象、バグっぽく見えるけど、本当にバグかどうか分からないし、どこがバグっているのかもイマイチ分からないので、こういうの悩ましいな、と思ったのでした。久々に変なの踏んだな。。。