Mojo::UserAgent - ノンブロッキングI/OのHTTPとWebSocketのユーザーエージェント
使い方
use Mojo::UserAgent;
# 良い粒度のレスポンスの処理(接続エラーの場合は、例外を発生)
my $ua = Mojo::UserAgent->new;
my $res = $ua->get('mojolicious.org/perldoc')->result;
if ($res->is_success) { say $res->body }
elsif ($res->is_error) { say $res->message }
elsif ($res->code == 301) { say $res->headers->location }
else { say 'Whatever...' }
# Acceptヘッダをつけてユニコードのスノーマンにハローを言う
say $ua->get('www.☃.net?hello=there' => {Accept => '*/*'})->result->body;
# HTMLとXMLのリソースからCSSセレクタを使ってデータを抽出する
say $ua->get('www.perl.org')->result->dom->at('title')->text;
# 新しいサイトから最近のヘッドラインをスクレイピングする
say $ua->get('blogs.perl.org')
->result->dom->find('h2 > a')->map('text')->join("\n");
# コンテンツのついたIPv6のPUTリクエスト
my $tx = $ua->put('[::1]:3000' => {'Content-Type' => 'text/plain'} => 'Hi!');
# ベーシック認証によるすばやいJSON APIリクエスト
my $value = $ua->get('https://sri:t3st@example.com/test.json')->result->json;
# TLS証明書認証のついたJSON POST (application/json)
my $tx = $ua->cert('tls.crt')->key('tls.key')
->post('https://example.com' => json => {top => 'secret'});
# POSTフォーム (application/x-www-form-urlencoded)
my $tx = $ua->post('https://metacpan.org/search' => form => {q => 'mojo'});
# DuckDuckGoのanonymously through Torを検索
$ua->proxy->http('socks://127.0.0.1:9050');
say $ua->get('api.3g2upl4pq6kufc4m.onion/?q=mojolicious&format=json')
->result->json('/Abstract');
# UNIXドメインソケットを通したGETリクエスト"/tmp/myapp.sock" (スラッシュをパーセントエンコード)
say $ua->get('http+unix://%2Ftmp%2Fmyapp.sock/perldoc')->result->body;
# GitHubからMojoliciousをダウンロードするためにリダイレクトを設定
$ua->max_redirects(5)
->get('https://www.github.com/mojolicious/mojo/tarball/master')
->result->save_to('/home/sri/mojo.tar.gz');
# ノンブロッキングリクエスト
$ua->get('mojolicious.org' => sub {
my ($ua, $tx) = @_;
say $tx->result->dom->at('title')->text;
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
# ノンブロッキングな並列リクエスト(プロミスで同期)
my $mojo = $ua->get_p('mojolicious.org');
my $cpan = $ua->get_p('cpan.org');
Mojo::Promise->all($mojo, $cpan)->then(sub {
my ($mojo, $cpan) = @_;
say $mojo->[0]->result->dom->at('title')->text;
say $cpan->[0]->result->dom->at('title')->text;
})->wait;
# UNIXドメインソケットを通してJSONメッセージを受信・送信するためのノンブロッキングなWebSocket接続
$ua->websocket('ws+unix://%2Ftmp%2Fmyapp.sock/echo.json' => sub {
my ($ua, $tx) = @_;
say 'WebSocket handshake failed!' and return unless $tx->is_websocket;
$tx->on(json => sub {
my ($tx, $hash) = @_;
say "WebSocket message via JSON: $hash->{msg}";
$tx->finish;
});
$tx->send({json => {msg => 'Hello World!'}});
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
説明
Mojo::UserAgent は完全な特徴を備えたノンブロッキングI/OのHTTPと WebSocketのユーザーエージェントです。 IPv6, TLS, SNI, IDNA, HTTP/SOCKS5プロキシ、Unixドメインソケット Comet (ロングポーリング), キープアライブ, コネクションポーリング, タイムアウト, クッキー、マルチパート、プロシキ、gzip圧縮、複数のイベントループをサポートしています。
すべての接続は、新しいプロセスがフォークされれば、自動的にリセットされます。 これは複数のプロセスが、同じMojo::UserAgentオブジェクトを安全に共有する ことを許可します。
よりよいスケーラビリティ(epoll, kqueue)、ノンブロッキングの名前解決、 SOCK5、TLSサポートも以下のモジュールによってサポートされます。 オプションのモジュールとしてEV(4.0+), Net::DNS::Native (0.15+) IO::Socket::SSL(2.009+),IO::Socket::Socks (0.64+)、IO::Socket::SSL (1.94+)が 透過的にサポートされ、インストールされていれば利用されます。 個々の機能はMOJO_NO_NDN、MOJO_NO_IPV6とMOJO_NO_TLS環境変数で無効にすることもできます。
イベント
Mojo::UserAgentはMojo::EventEmitterを継承しており、次のイベントが発生します。
prepare
$ua->on(prepare => sub {
my ($ua, $tx) = @_;
...
});
新しいトランザクションが準備されているときはいつでも、相対URLが書き換えられ、クッキーが追加される前に発行されます。 これは自動的に準備されたプロキシのCONNECTリクエストとそれに続くリダイレクトを含みます
$ua->on(prepare => sub {
my ($ua, $tx) = @_;
$tx->req->url(Mojo::URL->new('/mock-mojolicious'))
if $tx->req->url->host eq 'mojolicious.org';
});
start
$ua->on(start => sub {
my ($ua, $tx) = @_;
...
});
新しいトランザクションがまさに開始しようとしているときにいつでも発生します。 これは自動的に準備されるプロキシのCONNECTリクエストとレスポンス、それに続くリダイレクトも含みます。
$ua->on(start => sub {
my ($ua, $tx) = @_;
$tx->req->headers->header('X-Bender', 'Bite my shiny metal ass!');
});
属性
Mojo::UserAgent は以下の属性を実装しています。
ca
my $ca = $ua->ca;
$ua = $ua->ca('/etc/tls/ca.crt');
TLS認証局ファイルへのパス。 デフォルトはMOJO_CA_FILE環境変数の値。 ホスト名の検証も有効にします。
# デバッグで認証局を表示する
IO::Socket::SSL::set_ctx_defaults(
SSL_verify_callback => sub { say "Authority: $_[2]" and return $_[0] });
cert
my $cert = $ua->cert;
$ua = $ua->cert('tls.crt');
TLS証明書ファイルへのパス。デフォルトは MOJO_CERT_FILE の値です。
connect_timeout
my $timeout = $ua->connect_timeout; $ua = $ua->connect_timeout(5);
接続が確立されるまでの最大秒数。デフォルトはMOJO_CONNECT_TIMEOUT環境変数 の値か10です。
cookie_jar
my $cookie_jar = $ua->cookie_jar; $ua = $ua->cookie_jar(Mojo::CookieJar->new);
このユーザーエージェントのリクエストのためのクッキージャー。 デフォルトは Mojo::CookieJar オブジェクトです。
# すべてのクッキーを無効にする
$ua->cookie_jar->ignore(sub { 1 });
# パブリックなサフィックスのためにクッキーを無視する
my $ps = IO::Socket::SSL::PublicSuffix->default;
$ua->cookie_jar->ignore(sub {
my $cookie = shift;
return undef unless my $domain = $cookie->domain;
return ($ps->public_suffix($domain))[0] eq '';
});
# ジャーにカスタムクッキーを追加する
$ua->cookie_jar->add(
Mojo::Cookie::Response->new(
name => 'foo',
value => 'bar',
domain => 'mojolicio.us',
path => '/perldoc'
)
);
inactivity_timeout
my $timeout = $ua->inactivity_timeout; $ua = $ua->inactivity_timeout(15);
接続がドロップする前に非アクティブでいる最大の秒数。 デフォルトはMOJO_INACTIVITY_TIMEOUT環境変数の値か20です。 この値を0に設定すると接続を永久に非アクティブにしたままにすることができます。
insecure
my $bool = $ua->insecure; $ua = $ua->insecure($bool);
Do not require a valid TLS certificate to access HTTPS/WSS sites, defaults to the value of the MOJO_INSECURE environment variable.
HTTPS / WSSサイトにアクセスするために有効なTLS証明書を必要としません。デフォルトは MOJO_INSECURE環境変数の値です。
# テスト用にTLS証明書の検証を無効にする
say $ua->insecure(1)->get('https://127.0.0.1:3000')->result->code;
ioloop
my $loop = $ua->ioloop; $ua = $ua->ioloop(Mojo::IOLoop->new);
I/O 処理のために利用されるループオブジェクト。デフォルトは Mojo::IOLoop オブジェクトが利用されます。
key
my $key = $ua->key;
$ua = $ua->key('/etc/tls/client.crt');
TLS キーファイルへのパス。デフォルトは MOJO_KEY_FILE環境変数の値です。
local_address
my $address = $ua->local_address;
$ua = $ua->local_address('127.0.0.1');
バインドされているローカルアドレス。
max_connections
my $max_connections = $ua->max_connections; $ua = $ua->max_connections(5);
ユーザーエージェントが、最も古いキャッシュされた接続を閉じ始めるまでに 保有するキープアライブ接続の最大数。デフォルトは 5。この値を0に設定するとすべての接続がケプトアライブになることを防ぎます。
max_redirects
my $max_redirects = $ua->max_redirects; $ua = $ua->max_redirects(3);
ユーザーエージェントが、失敗する前までに辿るリダイレクトの最大数。 デフォルトは MOJO_MAX_REDIRECTS の値、または 0 です。
max_response_size
my $max = $ua->max_response_size; $ua = $ua->max_response_size(16777216);
最大応答サイズ(バイト)。デフォルトはMojo::Message::Responseの"max_message_size"の値です。 この値を0に設定すると、無限のサイズのレスポンスを許可します。 この値を増加させると、劇的にメモリの使用量が増えることに注意してください。たとえば、とても大きなサイズのレスポンスボディを、Mojo::Messageの"dom"や"json"で解析しようとした場合などです。
proxy
my $proxy = $ua->proxy; $ua = $ua->proxy(Mojo::UserAgent::Proxy->new);
プロキシマネージャー。デフォルトはMojo::UserAgent::Proxyオブジェクト。
# 環境からプロキシサーバーを検知します。
$ua->proxy->detect;
# 手動でHTTPプロキシを設定(HTTPS/WebSocketsのためにCONNECTを使う)
$ua->proxy->http('http://127.0.0.1:8080')->https('http://127.0.0.1:8080');
# Tor(SOCKS5)のための手動での設定
$ua->proxy->http('socks://127.0.0.1:9050')->https('socks://127.0.0.1:9050');
# 手動でUNIXドメインソケットを設定する(HTTPS/WebSocketsのためにCONNECTを使います)
$ua->proxy->http('http+unix://%2Ftmp%2Fproxy.sock')
->https('http+unix://%2Ftmp%2Fproxy.sock');
request_timeout
my $timeout = $ua->request_timeout; $ua = $ua->request_timeout(5);
「接続が確立、リクエストが送信、完全なレスポンスを受けとる」ことがキャンセルされるまでの 最大秒数。デフォルトは、MOJO_REQUEST_TIMEOUT環境変数の値か0。 この値を0に設定すると、ユーザーエージェントが無限に待つことを許可します。 タイムアウトはすべての続くリダイレクトにおいてリセットされます。
# 全体の制限は5秒、接続には3秒が費やされるかもしれない。 $ua->max_redirects(0)->connect_timeout(3)->request_timeout(5);
server
my $server = $ua->server; $ua = $ua->server(Mojo::UserAgent::Server->new);
アプリケーションサーバーの相対URLが一緒に処理されます。 デフォルトはMojo::UserAgent::Serverです。
# Webサービスをモックする
$ua->server->app(Mojolicious->new);
$ua->server->app->routes->get('/time' => sub {
my $c = shift;
$c->render(json => {now => time});
});
my $time = $ua->get('/time')->result->json->{now};
# ログレベルの変更
$ua->server->app->log->level('fatal');
# 相対URLのブロッキングを処理するために現在利用されているポート
say $ua->server->url->port;
# 相対URLのノンブロッキングを処理するために現在利用されているポート
say $ua->server->nb_url->port;
transactor
my $t = $ua->transactor; $ua = $ua->transactor(Mojo::UserAgent::Transactor->new);
トランザクションビルダー。 デフォルトはMojo::UserAgent::Transactorオブジェクトです。
# ユーザーエージェントの名前を変更
$ua->transactor->name('MyUA 1.0');
# 圧縮を無効にする
$ua->transactor->compressed(0);
メソッド
Mojo::UserAgent は Mojo::EventEmitter のすべてのメソッドを継承しており、 以下の新しいメソッドを実装しています。
build_tx
my $tx = $ua->build_tx(GET => 'example.com');
my $tx = $ua->build_tx(
PUT => 'http://example.com' => {Accept => '*/*'} => 'Content!');
my $tx = $ua->build_tx(
PUT => 'http://example.com' => {Accept => '*/*'} => form => {a => 'b'});
my $tx = $ua->build_tx(
PUT => 'http://example.com' => {Accept => '*/*'} => json => {a => 'b'});
Mojo::UserAgent::Transactorのtxメソッドで Mojo::Transaction::HTTPオブジェクトを生成します。
# カスタムクッキーを持ったリクエスト
my $tx = $ua->build_tx(GET => 'https://example.com/account');
$tx->req->cookies({name => 'user', value => 'sri'});
$tx = $ua->start($tx);
# gzip圧縮を非アクティブにする
my $tx = $ua->build_tx(GET => 'example.com');
$tx->req->headers->remove('Accept-Encoding');
$tx = $ua->start($tx);
# ひとつのエラーを発生することによって、レスポンスを中断する
my $tx = $ua->build_tx(GET => 'example.com');
$tx->res->on(progress => sub {
my $res = shift;
return unless my $server = $res->headers->server;
$res->error({message => 'Oh noes, it is IIS!'}) if $server =~ /IIS/;
});
$tx = $ua->start($tx);
build_websocket_tx
my $tx = $ua->build_websocket_tx('ws://example.com');
my $tx = $ua->build_websocket_tx(
'ws://example.com' => {DNT => 1} => ['v1.proto']);
Mojo::UserAgent::Transactorのwebsocketメソッドで Mojo::Transaction::HTTPオブジェクトを生成します。
# クッキーを持ったWebSocketハンドシェイク
my $tx = $ua->build_websocket_tx('wss://example.com/echo');
$tx->req->cookies({name => 'user', value => 'sri'});
$ua->start($tx => sub {
my ($ua, $tx) = @_;
say 'WebSocket handshake failed!' and return unless $tx->is_websocket;
$tx->on(message => sub {
my ($tx, $msg) = @_;
say "WebSocket message: $msg";
$tx->finish;
});
$tx->send('Hi!');
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
delete
my $tx = $ua->delete('example.com');
my $tx = $ua->delete('http://example.com' => {Accept => '*/*'} => 'Hi!');
my $tx = $ua->delete(
'http://example.com' => {Accept => '*/*'} => form => {a => 'b'});
my $tx = $ua->delete(
'http://example.com' => {Accept => '*/*'} => json => {a => 'b'});
ブロッキングするDELETEリクエストを実行し、結果であるMojo::Transaction::HTTPオブジェクト を返却します。 (メソッドを除いて)Mojo::UserAgent::Transactorのtxとまったく同じ引数を受け取ります。 ノンブロッキングのリクエストを実行するため、コールバックを追加することも できます。
$ua->delete('http://example.com' => json => {a => 'b'} => sub {
my ($ua, $tx) = @_;
say $tx->result->body;
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
delete_p
my $promise = $ua->delete_p('http://example.com');
Same as "delete", but performs all requests non-blocking and returns a Mojo::Promise object instead of accepting a callback.
"delete"と同じですが、すべてのリクエストをノンブロッキングで実行し、 コールバックを受け付ける代わりに、Mojo::Promiseオブジェクトを返します。
$ua->delete_p('http://example.com' => json => {a => 'b'})->then(sub {
my $tx = shift;
say $tx->result->body;
})->catch(sub {
my $err = shift;
warn "Connection error: $err";
})->wait;
get
my $tx = $ua->get('example.com');
my $tx = $ua->get('http://example.com' => {Accept => '*/*'} => 'Hi!');
my $tx = $ua->get(
'http://example.com' => {Accept => '*/*'} => form => {a => 'b'});
my $tx = $ua->get(
'http://example.com' => {Accept => '*/*'} => json => {a => 'b'});
ブロッキングするHTTP GETリクエストを実行し、結果であるMojo::Transaction::HTTPオブジェクト を返却します。 (メソッドを除いて)Mojo::UserAgent::Transactorのtxとまったく同じ引数を受け取ります。 ノンブロッキングのリクエストを実行するため、コールバックを追加することも できます。
$ua->get('http://example.com' => json => {a => 'b'} => sub {
my ($ua, $tx) = @_;
say $tx->result->body;
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
get_p
my $promise = $ua->get_p('http://example.com');
"get"と同じですが、すべてのリクエストをノンブロッキングで実行し、 コールバックを受け付ける代わりに、Mojo::Promiseオブジェクトを返します。
$ua->get_p('http://example.com' => json => {a => 'b'})->then(sub {
my $tx = shift;
say $tx->result->body;
})->catch(sub {
my $err = shift;
warn "Connection error: $err";
})->wait;
head
my $tx = $ua->head('example.com');
my $tx = $ua->head('http://example.com' => {Accept => '*/*'} => 'Hi!');
my $tx = $ua->head(
'http://example.com' => {Accept => '*/*'} => form => {a => 'b'});
my $tx = $ua->head(
'http://example.com' => {Accept => '*/*'} => json => {a => 'b'});
ブロッキングするHTTP HEADリクエストを実行し、結果であるMojo::Transaction::HTTPオブジェクト を返却します。 (メソッドを除いて)Mojo::UserAgent::Transactorのtxとまったく同じ引数を受け取ります。 ノンブロッキングのリクエストを実行するため、コールバックを追加することも できます。
$ua->head('http://example.com' => json => {a => 'b'} => sub {
my ($ua, $tx) = @_;
say $tx->result->body;
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
head_p
my $promise = $ua->head_p('http://example.com');
"head"と同じですが、すべてのリクエストをノンブロッキングで実行し、 コールバックを受け付ける代わりに、Mojo::Promiseオブジェクトを返します。
$ua->head_p('http://example.com' => json => {a => 'b'})->then(sub {
my $tx = shift;
say $tx->result->body;
})->catch(sub {
my $err = shift;
warn "Connection error: $err";
})->wait;
options
my $tx = $ua->options('example.com');
my $tx = $ua->options('http://example.com' => {Accept => '*/*'} => 'Hi!');
my $tx = $ua->options(
'http://example.com' => {Accept => '*/*'} => form => {a => 'b'});
my $tx = $ua->options(
'http://example.com' => {Accept => '*/*'} => json => {a => 'b'});
ブロッキングするOPTIONSリクエストを実行し、結果であるMojo::Transaction::HTTPオブジェクト を返却します。 (メソッドを除いて)Mojo::UserAgent::Transactorのtxとまったく同じ引数を受け取ります。 ノンブロッキングのリクエストを実行するため、コールバックを追加することも できます。
$ua->options('http://example.com' => json => {a => 'b'} => sub {
my ($ua, $tx) = @_;
say $tx->result->body;
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
options_p
my $promise = $ua->options_p('http://example.com');
"options"と同じですが、すべてのリクエストをノンブロッキングで実行し、 コールバックを受け付ける代わりに、Mojo::Promiseオブジェクトを返します。
$ua->options_p('http://example.com' => json => {a => 'b'})->then(sub {
my $tx = shift;
say $tx->result->body;
})->catch(sub {
my $err = shift;
warn "Connection error: $err";
})->wait;
patch
my $tx = $ua->patch('example.com');
my $tx = $ua->patch('http://example.com' => {Accept => '*/*'} => 'Hi!');
my $tx = $ua->patch(
'http://example.com' => {Accept => '*/*'} => form => {a => 'b'});
my $tx = $ua->patch(
'http://example.com' => {Accept => '*/*'} => json => {a => 'b'});
ブロッキングするPATCHリクエストを実行し、結果であるMojo::Transaction::HTTPオブジェクト を返却します。 (メソッドを除いて)Mojo::UserAgent::Transactorのtxとまったく同じ引数を受け取ります。 ノンブロッキングのリクエストを実行するため、コールバックを追加することも できます。
$ua->patch('http://example.com' => json => {a => 'b'} => sub {
my ($ua, $tx) = @_;
say $tx->result->body;
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
patch_p
my $promise = $ua->patch_p('http://example.com');
"patch"と同じですが、すべてのリクエストをノンブロッキングで実行し、 コールバックを受け付ける代わりに、Mojo::Promiseオブジェクトを返します。
$ua->patch_p('http://example.com' => json => {a => 'b'})->then(sub {
my $tx = shift;
say $tx->result->body;
})->catch(sub {
my $err = shift;
warn "Connection error: $err";
})->wait;
post
my $tx = $ua->post('example.com');
my $tx = $ua->post('http://example.com' => {Accept => '*/*'} => 'Hi!');
my $tx = $ua->post(
'http://example.com' => {Accept => '*/*'} => form => {a => 'b'});
my $tx = $ua->post(
'http://example.com' => {Accept => '*/*'} => json => {a => 'b'});
ブロッキングするPOSTリクエストを実行し、結果であるMojo::Transaction::HTTPオブジェクト を返却します。 (メソッドを除いて)Mojo::UserAgent::Transactorのtxとまったく同じ引数を受け取ります。 ノンブロッキングのリクエストを実行するため、コールバックを追加することも できます。
$ua->post('http://example.com' => json => {a => 'b'} => sub {
my ($ua, $tx) = @_;
say $tx->result->body;
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
post_p
my $promise = $ua->post_p('http://example.com');
"post"と同じですが、すべてのリクエストをノンブロッキングで実行し、 コールバックを受け付ける代わりに、Mojo::Promiseオブジェクトを返します。
$ua->post_p('http://example.com' => json => {a => 'b'})->then(sub {
my $tx = shift;
say $tx->result->body;
})->catch(sub {
my $err = shift;
warn "Connection error: $err";
})->wait;
put
my $tx = $ua->put('example.com');
my $tx = $ua->put('http://example.com' => {Accept => '*/*'} => 'Hi!');
my $tx = $ua->put(
'http://example.com' => {Accept => '*/*'} => form => {a => 'b'});
my $tx = $ua->put(
'http://example.com' => {Accept => '*/*'} => json => {a => 'b'});
ブロッキングするPUTリクエストを実行し、結果であるMojo::Transaction::HTTPオブジェクト を返却します。 (メソッドを除いて)Mojo::UserAgent::Transactorのtxとまったく同じ引数を受け取ります。 ノンブロッキングのリクエストを実行するため、コールバックを追加することも できます。
$ua->put('http://example.com' => json => {a => 'b'} => sub {
my ($ua, $tx) = @_;
say $tx->result->body;
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
put_p
my $promise = $ua->put_p('http://example.com');
"put"と同じですが、すべてのリクエストをノンブロッキングで実行し、 コールバックを受け付ける代わりに、Mojo::Promiseオブジェクトを返します。
$ua->put_p('http://example.com' => json => {a => 'b'})->then(sub {
my $tx = shift;
say $tx->result->body;
})->catch(sub {
my $err = shift;
warn "Connection error: $err";
})->wait;
start
my $tx = $ua->start(Mojo::Transaction::HTTP->new);
カスタムのMojo::Transaction::HTTPオブジェクトのためにブロッキングするリクエストを処理します。 ノンブロッキングのトランザクションを実行するため、コールバックを追加することも できます。
my $tx = $ua->build_tx(GET => 'http://example.com');
$ua->start($tx => sub {
my ($ua, $tx) = @_;
say $tx->result->body;
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
start_p
my $promise = $ua->start_p(Mojo::Transaction::HTTP->new);
"start"と同じですが、すべてのリクエストをノンブロッキングで実行し、 コールバックを受け付ける代わりに、Mojo::Promiseオブジェクトを返します。
my $tx = $ua->build_tx(GET => 'http://example.com');
$ua->start_p($tx)->then(sub {
my $tx = shift;
say $tx->result->body;
})->catch(sub {
my $err = shift;
warn "Connection error: $err";
})->wait;
websocket
$ua->websocket('ws://example.com' => sub {...});
$ua->websocket(
'ws://example.com' => {DNT => 1} => ['v1.proto'] => sub {...});
透過的なハンドシェイクでノンブロッキングのWebSocket接続をオープンします。 Mojo::UserAgent::Transactorのwebsocketとまったく同じ引数を受け取ります。 コールバックは、ハンドシェイクが成功しかたに依存して、Mojo::Transaction::WebSocketオブジェクトかMojo::Transaction::HTTPオブジェクトを受け取ります。
$ua->websocket('wss://example.com/echo' => ['v1.proto'] => sub {
my ($ua, $tx) = @_;
say 'WebSocket handshake failed!' and return unless $tx->is_websocket;
say 'Subprotocol negotiation failed!' and return unless $tx->protocol;
$tx->on(finish => sub {
my ($tx, $code, $reason) = @_;
say "WebSocket closed with status $code.";
});
$tx->on(message => sub {
my ($tx, $msg) = @_;
say "WebSocket message: $msg";
$tx->finish;
});
$tx->send('Hi!');
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
Sec-WebSocket-Extensionsを設定することによって、 permessage-deflate圧縮をアクティブにすることができます。 これはよりよりパフォーマンスをもたらすでしょう。 しかし、コネクションあたりメモリ使用率は300KB上昇します。
$ua->websocket('ws://example.com/foo' => {
'Sec-WebSocket-Extensions' => 'permessage-deflate'
} => sub {...});
websocket_p
my $promise = $ua->websocket_p('ws://example.com');
"websocket"と同じですが、すべてのリクエストをノンブロッキングで実行し、 コールバックを受け付ける代わりに、Mojo::Promiseオブジェクトを返します。
$ua->websocket_p('wss://example.com/echo')->then(sub {
my $tx = shift;
my $promise = Mojo::Promise->new;
$tx->on(finish => sub { $promise->resolve });
$tx->on(message => sub {
my ($tx, $msg) = @_;
say "WebSocket message: $msg";
$tx->finish;
});
$tx->send('Hi!');
return $promise;
})->catch(sub {
my $err = shift;
warn "WebSocket error: $err";
})->wait;
デバッグ
いくらかの発展的な詳細な情報をSTDERRに出力するために、 MOJO_USERAGENT_DEBUG環境変数を設定することができます。
MOJO_USERAGENT_DEBUG=1
参考
Mojolicious, Mojolicious::Guides, http://mojolicio.us.
(Mojolicious 8.12を反映。2019年5月30日更新)
Mojoliciousドキュメント日本語訳