TABLE OF CONTENTS

NAME

Mojo::UserAgent - Non-blocking I/O HTTP and WebSocket user agent

SYNOPSIS

use Mojo::UserAgent;

# 如果方法后面直接跟一个哈希引用, 表示所要发送的定制的 header

# 对 Unicode snowman 发关 hello 的参数,并加上 "Do Not Track" 的 header 
my $ua = Mojo::UserAgent->new;
say $ua->get('www.☃.net?hello=there' => {DNT => 1})->res->body;

# 对 Form POST 进行异常处理
my $tx = $ua->post('search.cpan.org/search' => form => {q => 'mojo'});
if (my $res = $tx->success) { say $res->body }
else {
  my ($err, $code) = $tx->error;
  die "$err->{code} response: $err->{message}" if $err->{code};
  die "Connection error: $err->{message}";
}

# 使用 Basic authentication 发出的 JSON 的 API 请求
say $ua->get('https://sri:s3cret@search.twitter.com/search.json?q=perl')
  ->res->json('/results/0/text');

# 从 HTML 和 XML 的资源中提取数据
say $ua->get('www.perl.org')->res->dom->html->head->title->text;

# 对这个新闻站点剥下最新的头条信息, 这使用了 CSS 的选择器
say $ua->get('perlnews.org')->res->dom('h2 > a')->text->shuffle;

# IPv6 PUT request with content
my $tx
  = $ua->put('[::1]:3000' => {'Content-Type' => 'text/plain'} => 'Hello!');

# 取得最新的 Mojolicious
$ua->max_redirects(5)->get('latest.mojolicio.us')
  ->res->content->asset->move_to('/Users/sri/mojo.tar.gz');

# TLS certificate authentication and JSON POST
# 使用 TLS 的认证和使用 JSON 的 POST
my $tx = $ua->cert('tls.crt')->key('tls.key')
  ->post('https://mojolicio.us' => json => {top => 'secret'});

# 非阻塞并发请求
my $delay = Mojo::IOLoop->delay(sub {
  my ($delay, @titles) = @_;
  say for @titles;
});
for my $url ('mojolicio.us', 'cpan.org') {
  my $end = $delay->begin(0);
  $ua->get($url => sub {
    my ($ua, $tx) = @_;
    $end->($tx->res->dom->at('title')->text);
  });
}
$delay->wait;

# Non-blocking WebSocket connection sending and receiving JSON messages
$ua->websocket('ws://example.com/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;

DESCRIPTION

Mojo::UserAgent 是一个全功能的非阻塞 I/O HTTP 和 WebSocket 的用户代理, 支持 IPv6, TLS, SNI, IDNA, Comet (long polling), keep-alive, connection pooling, timeout, cookie, multipart, proxy, gzip 压缩和多种事件循环支持.

如果一个新的进程 fork 产生时, 全部的连接相关的信息会被 reset. 所以这个允许多个进程安全的共享 Mojo::UserAgent 对象.

为了更好的可扩展性 (epoll, kqueue) 和支持 IPv6 与 TLS, 可以在 Mojo::IOLoop 中可选的模块 EV (4.0+), IO::Socket::IP (0.20+) 和 IO::Socket::SSL (1.84+) 会自动的发现. 单独的特性象 MOJO_NO_IPV6 和 MOJO_NO_TLS 可以通过环境变量来禁用.

Mojolicious::Guides::Cookbook 有更多信息.

事件

Mojo::UserAgent 继承全部的 Mojo::EventEmitter 的事件, 并支持下面这些.

error

$ua->on(error => sub {
  my ($ua, $err) = @_;
  ...
});

当如果有错误时, 整个事件就不在处理.

$ua->on(error => sub {
  my ($ua, $err) = @_;
  say "This looks bad: $err";
});

start

$ua->on(start => sub {
  my ($ua, $tx) = @_;
  ...
});

当任何新的事务处理即将开始的时候, 但并没发出请求, 这包含自动的准备 proxy 的 CONNECT 请求和随后的重定向.

$ua->on(start => sub {
  my ($ua, $tx) = @_;
  $tx->req->headers->header('X-Bender' => 'Bite my shiny metal ass!');
});

属性

Mojo::UserAgent implements the following attributes.

ca

my $ca = $ua->ca;
$ua    = $ua->ca('/etc/tls/ca.crt');

指定 TLS 证书授权文件所在路径, 默认是 MOJO_CA_FILE 环境变量的值. 这也会也激活主机名验证.

# Show certificate authorities for debugging
IO::Socket::SSL::set_defaults(
  SSL_verify_callback => sub { say "Authority: $_[2]" and return $_[0] });

cert

my $cert = $ua->cert;
$ua      = $ua->cert('/etc/tls/client.crt');

指定 TLS 证书文件所在路径, 默认是 MOJO_CERT_FILE 环境变量的值.

connect_timeout

my $timeout = $ua->connect_timeout;
$ua         = $ua->connect_timeout(5);

最大的建立连接所需要的秒数, 如果超过会被取消, 默认是 MOJO_CONNECT_TIMEOUT 环境变量的值或者是 10.

my $cookie_jar = $ua->cookie_jar;
$ua            = $ua->cookie_jar(Mojo::UserAgent::CookieJar->new);

用于该用户代理的请求的 Cookie jar, 默认是 Mojo::UserAgent::CookieJar 对象.

# Disable cookie jar
$ua->cookie_jar(0);

inactivity_timeout

my $timeout = $ua->inactivity_timeout;
$ua         = $ua->inactivity_timeout(15);

最大的连接上去但不活跃的时间, 超过会被关闭. 默认为 MOJO_INACTIVITY_TIMEOUT 环境变量的值或者是 20. 如果设置成 0 的值会允许连接无限期地处于非活动状态.

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 = $ua->max_connections;
$ua     = $ua->max_connections(5);

在开始关掉老的缓存的连接之前用户代理的 UA 能保持最大活动连接的数量. 默认为 5.

max_redirects

my $max = $ua->max_redirects;
$ua     = $ua->max_redirects(3);

用户代理所能保持的最大的重定向的数量, 超出就会 fail. 默认是 MOJO_MAX_REDIRECTS 环境变量的值或者 0.

proxy

my $proxy = $ua->proxy;
$ua       = $ua->proxy(Mojo::UserAgent::Proxy->new);

代理管理, 默认是使用 Mojo::UserAgent::Proxy 的对象

# 自动发现代理服务从环境变量
$ua->proxy->detect;

request_timeout

my $timeout = $ua->request_timeout;
$ua         = $ua->request_timeout(5);

建议的连接所能保持最大的秒数, 发送请求并且等着接收时连接所能保持最秒数. 超过就会关闭. 默认使用 MOJO_REQUEST_TIMEOUT 环境变量的值或者 0. 设置这个值为 0 会无限期地等待直到接收. 这个超时会在每次重定向时重新 reset.

# Total limit of 5 seconds, of which 3 seconds may be spent connecting
$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 对象处理.

# Introspect
say for @{$ua->server->app->secrets};

# Change log level
$ua->server->app->log->level('fatal');

# Port currently used for processing relative URLs blocking
say $ua->server->url->port;

# Port currently used for processing relative URLs non-blocking
say $ua->server->nb_url->port;

transactor

my $t = $ua->transactor;
$ua   = $ua->transactor(Mojo::UserAgent::Transactor->new);

Transaction 默认是 Mojo::UserAgent::Transactor 对象.

METHODS

Mojo::UserAgent inherits all methods from Mojo::EventEmitter and implements the following new ones.

build_tx

my $tx = $ua->build_tx(GET => 'kraih.com');
my $tx = $ua->build_tx(PUT => 'http://kraih.com' => {DNT => 1} => 'Hi!');
my $tx = $ua->build_tx(
  PUT => 'http://kraih.com' => {DNT => 1} => form => {a => 'b'});
my $tx = $ua->build_tx(
  PUT => 'http://kraih.com' => {DNT => 1} => json => {a => 'b'});

"tx" in Mojo::UserAgent::Transactor 用于生成 Mojo::Transaction::HTTP 对象.

# Request with cookie
my $tx = $ua->build_tx(GET => 'kraih.com');
$tx->req->cookies({name => 'foo', value => 'bar'});
$ua->start($tx);

build_websocket_tx

my $tx = $ua->build_websocket_tx('ws://localhost:3000');
my $tx = $ua->build_websocket_tx('ws://localhost:3000' => {DNT => 1});

"websocket" in Mojo::UserAgent::Transactor 用于生成 Mojo::Transaction::HTTP 对象.

delete

my $tx = $ua->delete('kraih.com');
my $tx = $ua->delete('http://kraih.com' => {DNT => 1} => 'Hi!');
my $tx = $ua->delete(
  'http://kraih.com' => {DNT => 1} => form => {a => 'b'});
my $tx = $ua->delete(
  'http://kraih.com' => {DNT => 1} => json => {a => 'b'});

执行阻塞的 HTTP DELETE 请求并返回 Mojo::Transaction::HTTP 的对象, 使用 "tx" in Mojo::UserAgent::Transactor 相同的参数 ( 除了方法 ). 你可以在后面加入回调来执行请求非阻塞的请求.

$ua->delete('http://kraih.com' => sub {
  my ($ua, $tx) = @_;
  say $tx->res->body;
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;

get

my $tx = $ua->get('kraih.com');
my $tx = $ua->get('http://kraih.com' => {DNT => 1} => 'Hi!');
my $tx = $ua->get('http://kraih.com' => {DNT => 1} => form => {a => 'b'});
my $tx = $ua->get('http://kraih.com' => {DNT => 1} => json => {a => 'b'});

同上, 执行的是 HTTP GET 的请求.

$ua->get('http://kraih.com' => sub {
  my ($ua, $tx) = @_;
  say $tx->res->body;
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
my $tx = $ua->head('kraih.com');
my $tx = $ua->head('http://kraih.com' => {DNT => 1} => 'Hi!');
my $tx = $ua->head('http://kraih.com' => {DNT => 1} => form => {a => 'b'});
my $tx = $ua->head('http://kraih.com' => {DNT => 1} => json => {a => 'b'});

同上, 执行的是 HTTP HEAD 的请求.

$ua->head('http://kraih.com' => sub {
  my ($ua, $tx) = @_;
  say $tx->res->body;
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;

options

my $tx = $ua->options('example.com');
my $tx = $ua->options('http://example.com' => {DNT => 1} => 'Hi!');
my $tx = $ua->options(
  'http://example.com' => {DNT => 1} => form => {a => 'b'});
my $tx = $ua->options(
  'http://example.com' => {DNT => 1} => json => {a => 'b'});

同上, 执行的是 HTTP OPTIONS 的请求.

$ua->options('http://example.com' => sub {
  my ($ua, $tx) = @_;
  say $tx->res->body;
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;

patch

my $tx = $ua->patch('kraih.com');
my $tx = $ua->patch('http://kraih.com' => {DNT => 1} => 'Hi!');
my $tx = $ua->patch('http://kraih.com' => {DNT => 1} => form => {a => 'b'});
my $tx = $ua->patch('http://kraih.com' => {DNT => 1} => json => {a => 'b'});

同上, 执行的是 HTTP PATCH 的请求.

$ua->patch('http://kraih.com' => sub {
  my ($ua, $tx) = @_;
  say $tx->res->body;
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;

post

my $tx = $ua->post('kraih.com');
my $tx = $ua->post('http://kraih.com' => {DNT => 1} => 'Hi!');
my $tx = $ua->post('http://kraih.com' => {DNT => 1} => form => {a => 'b'});
my $tx = $ua->post('http://kraih.com' => {DNT => 1} => json => {a => 'b'});

同上, 执行的是 HTTP POST 的请求.

$ua->post('http://kraih.com' => sub {
  my ($ua, $tx) = @_;
  say $tx->res->body;
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;

put

my $tx = $ua->put('kraih.com');
my $tx = $ua->put('http://kraih.com' => {DNT => 1} => 'Hi!');
my $tx = $ua->put('http://kraih.com' => {DNT => 1} => form => {a => 'b'});
my $tx = $ua->put('http://kraih.com' => {DNT => 1} => json => {a => 'b'});

同上, 执行的是 HTTP PUT 的请求.

$ua->put('http://kraih.com' => sub {
  my ($ua, $tx) = @_;
  say $tx->res->body;
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;

start

my $tx = $ua->start(Mojo::Transaction::HTTP->new);

执行阻塞的请求. 你可以在后面加一个回调来执行非阻塞的请求.

my $tx = $ua->build_tx(GET => 'http://kraih.com');
$ua->start($tx => sub {
  my ($ua, $tx) = @_;
  say $tx->res->body;
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;

websocket

$ua->websocket('ws://localhost:3000' => sub {...});
$ua->websocket('ws://localhost:3000' => {DNT => 1} => sub {...});

Open a non-blocking WebSocket connection with transparent handshake, takes the same arguments as "websocket" in Mojo::UserAgent::Transactor. The callback will receive either a Mojo::Transaction::WebSocket or Mojo::Transaction::HTTP object.

$ua->websocket('ws://localhost:3000/echo' => sub {
  my ($ua, $tx) = @_;
  say 'WebSocket handshake failed!' and return unless $tx->is_websocket;
  $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;

DEBUGGING

你可以打开 MOJO_USERAGENT_DEBUG 的环境变量来进行高级的调试信息, 默认会输出到标准错误.

MOJO_USERAGENT_DEBUG=1

SEE ALSO

Mojolicious, Mojolicious::Guides, http://mojolicio.us.