前の続き。
LWP::UserAgentを眺めていたら
http://perldoc.jp/docs/modules/libwww-perl-5.813/LWP/UserAgent.pod#item__ua__gt_get___url__
:content_cb
オプションでコールバック関数が指定されると、
レスポンスの内容の塊ををサーバから受信する毎にこの関数が呼び出されます。
これらのオプションのどちらも指定されなかった場合、レスポンスの内容は
レスポンスオブジェクト自身に蓄積されます。
これはレスポンスボディがとても大きい場合には向いていません。
':content_cb'でコールバックを指定すればLWPでもいけるんじゃ?
以下で試してみる。
my $ua = new LWP::UserAgent(); my $header = makeOAuthHeader(...); # Authorizationヘッダ部分 my $buffer; # コールバック関数内で使用するバッファを先に生成 $ua->get('https://userstream.twitter.com/2/user.json', "Authorization"=>$header, "Content-Type" => "application/x-www-form-urlencoded", ":content_cb" => sub{ $buffer .= shift; my $re = shift; printf STDERR ("as_string: %s\n", $re->as_string); # ヘッダ部分とコンテンツ部分を出力 while($buffer =~/(.+?\n)/g){ my $line = $1; print "$line"; } $buffer = substr($buffer, rindex($buffer,"\n")+1); } );
改行コードを"\n"で決めうちしている点でちょっと雑だけど、
こんな感じにやってみるとうまい具合に標準出力にJSONデータが出力された。
HTTP::Request->as_stringでHTTPレスポンスヘッダ部分とコンテンツ部分を確認してみても、
ヘッダ部分は一番最初に取得した状態を記憶しているだけで、コンテンツ部分はコールバックされるたびにクリアされているので、
バッファがあふれる可能性は低い。
コールバック関数が呼ばれるタイミングは、1行毎ではなく':read_size_hint'の大きさに依存する。
なので、自前でバッファを作って、改行データまでを1データとしてwhileで回して処理すればよい。
$buffer = substr($buffer, rindex($buffer,"\n")+1);の部分は、
もし、改行が見つからない場合はrindex()は-1となり、結果に+1されるので0になる。
substrで得られるのは本来の文字列になるので、バッファは書き換わらない事になる。
本来ならif文で分けるべきだが、面倒なのでry
1行あたりのデータの最大サイズが決まっているのであればいいんだけど、
中身はテキストデータだし、そこまで大きすぎることはないか。