转储 WWW::Curl::Easy 请求
Dump WWW::Curl::Easy request
我使用包 WWW::Curl::Easy
进行 API 调用,这是我的示例代码:
use WWW::Curl::Easy;
my $curl = WWW::Curl::Easy->new();
$curl->setopt(CURLOPT_POST, 1);
$curl->setopt(CURLOPT_HEADER, 1);
$curl->setopt(CURLOPT_HTTPHEADER, ['Accept: text/xml; charset=utf-8', 'Content-Type:text/xml; charset=utf-8', 'SOAPAction: "importSheet"']);
$curl->setopt(CURLOPT_POSTFIELDS, $requestMessage);
$curl->setopt(CURLOPT_URL, $tom::{'setup'}{'api'}{'carrier'}{'url'});
my $response;
$curl->setopt(CURLOPT_WRITEDATA, $response);
main::_log(Dumper($curl));
my $ret = $curl->perform();
我能以某种方式转储来自 $curl
的整个请求吗?
我尝试了 main::_log(Dumper($curl));
但它没有给我任何有用的东西。
我希望看到整个请求,例如真实的 headers、方法、请求的 body、post 数据等。我知道我可以在代码中看到这些信息,因为我例如在 CURLOPT_HTTPHEADER
中设置它,但我想转储将要发送的“真实”请求(来自 curl)。
最简单的方法是在您的程序中打开 CURLOPT_VERBOSE
。
use WWW::Curl::Easy;
my $curl = WWW::Curl::Easy->new;
$curl->setopt(CURLOPT_HEADER,1);
$curl->setopt(CURLOPT_URL, 'http://example.com');
$curl->setopt(CURLOPT_WRITEDATA,\my $response_body);
# this turns on debugging a la `curl -v http://example.com`
$curl->setopt(CURLOPT_VERBOSE, 1);
my $retcode = $curl->perform;
print("Transfer went ok\n") unless $retcode;
输出:
* Trying 93.184.216.34:80...
* TCP_NODELAY set
* Connected to example.com (93.184.216.34) port 80 (#0)
> GET / HTTP/1.1
Host: example.com
Accept: */*
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Age: 543595
< Cache-Control: max-age=604800
< Content-Type: text/html; charset=UTF-8
< Date: Thu, 25 Nov 2021 14:20:18 GMT
< Etag: "3147526947+gzip"
< Expires: Thu, 02 Dec 2021 14:20:18 GMT
< Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
< Server: ECS (nyb/1D0F)
< Vary: Accept-Encoding
< X-Cache: HIT
< Content-Length: 1256
<
* Connection #0 to host example.com left intact
Transfer went ok
如果你想要更花哨的东西,你必须自己动手。您可以通过将 CURLOPT_DEBUGFUNCTION
设置为 Perl 代码引用来覆盖 CURLOPT_VERBOSE
所做的事情。每行调试输出都会调用它。
签名似乎与 libcurl 文档中的不同,但可以推断出发生了什么。
$curl->setopt(CURLOPT_VERBOSE, 1);
$curl->setopt(CURLOPT_DEBUGFUNCTION, sub {
use Data::Dumper;
print Dumper \@_;
});
此集合的前几行输出如下所示。
[
[0] " Trying 93.184.216.34:80...
",
[1] undef,
[2] 0
]
[
[0] "TCP_NODELAY set
",
[1] undef,
[2] 0
]
[
[0] "Connected to example.com (93.184.216.34) port 80 (#0)
",
[1] undef,
[2] 0
]
[
[0] "GET / HTTP/1.1
Host: example.com
Accept: */*
",
[1] undef,
[2] 2
]
第一个参数似乎是文本。
根据文档,调试数据有几种类型。
typedef enum {
CURLINFO_TEXT = 0,
CURLINFO_HEADER_IN, /* 1 */
CURLINFO_HEADER_OUT, /* 2 */
CURLINFO_DATA_IN, /* 3 */
CURLINFO_DATA_OUT, /* 4 */
CURLINFO_SSL_DATA_IN, /* 5 */
CURLINFO_SSL_DATA_OUT, /* 6 */
CURLINFO_END
} curl_infotype;
鉴于我的最后一个示例有一个 2
并且所有其他示例都有一个 0
作为它们的第三个参数,我们可以假设这一定是类型。
我还没弄明白第二个参数是什么。
这给我们留下了:
$curl->setopt(CURLOPT_DEBUGFUNCTION, sub {
my ($text, undef, $type) = @_;
# ...
});
碰巧,这些类型已被 WWW::Curl::Easy 作为常量导入。所以我们可以做这样的事情来只得到传出的 header.
$curl->setopt(CURLOPT_DEBUGFUNCTION, sub {
my ($text, undef, $type) = @_;
print $text if $type == CURLINFO_HEADER_OUT;
});
这将输出:
$ /usr/bin/perl foo.pl
GET / HTTP/1.1
Host: example.com
Accept: */*
Transfer went ok
传入的 header 似乎一次只有一个,因此您可以过滤。
$curl->setopt(CURLOPT_DEBUGFUNCTION, sub {
my ($text, undef, $type) = @_;
if ($type == CURLINFO_HEADER_IN && $text =~ m/Etag: "(.+)"/) {
print "Etag is \n";
}
});
一个更复杂的例子是获取整个调试输出并将其转换为 HTTP::Request and HTTP::Response objects.
$curl->setopt(CURLOPT_WRITEDATA,$response_body);
$curl->setopt(CURLOPT_VERBOSE, 1);
my ($req, $res);
$curl->setopt(CURLOPT_DEBUGFUNCTION, sub {
my ($text, undef, $type) = @_;
require HTTP::Request;
require HTTP::Response;
if ($type == CURLINFO_HEADER_OUT) {
$req = HTTP::Request->parse($text);
} elsif ($type == CURLINFO_DATA_OUT) {
$req->content($text);
} elsif ($type == CURLINFO_HEADER_IN) {
unless ($res) {
$res = HTTP::Response->parse($text);
$res->request($req);
return 0; # this is retcode
}
# this is from HTTP::Message
# (https://metacpan.org/dist/HTTP-Message/source/lib/HTTP/Message.pm#L60)
my @hdr;
while (1) {
if ($text =~ s/^([^\s:]+)[ \t]*: ?(.*)\n?//) {
push(@hdr, , );
$hdr[-1] =~ s/\r\z//;
}
elsif (@hdr && $text =~ s/^([ \t].*)\n?//) {
$hdr[-1] .= "\n";
$hdr[-1] =~ s/\r\z//;
}
else {
$text =~ s/^\r?\n//;
last;
}
}
$res->header(@hdr) if @hdr;
} elsif ($type == CURLINFO_DATA_IN) {
$res->content($text);
}
return 0; # this is retcode
});
这将为您提供一个 HTTP::Request 和一个 HTTP::Response object,每个都包含所有 header 和内容。不确定这是否有用,但它很好地演示了此功能的可能性。
免责声明:我是 libwww-perl.
的维护者
我使用包 WWW::Curl::Easy
进行 API 调用,这是我的示例代码:
use WWW::Curl::Easy;
my $curl = WWW::Curl::Easy->new();
$curl->setopt(CURLOPT_POST, 1);
$curl->setopt(CURLOPT_HEADER, 1);
$curl->setopt(CURLOPT_HTTPHEADER, ['Accept: text/xml; charset=utf-8', 'Content-Type:text/xml; charset=utf-8', 'SOAPAction: "importSheet"']);
$curl->setopt(CURLOPT_POSTFIELDS, $requestMessage);
$curl->setopt(CURLOPT_URL, $tom::{'setup'}{'api'}{'carrier'}{'url'});
my $response;
$curl->setopt(CURLOPT_WRITEDATA, $response);
main::_log(Dumper($curl));
my $ret = $curl->perform();
我能以某种方式转储来自 $curl
的整个请求吗?
我尝试了 main::_log(Dumper($curl));
但它没有给我任何有用的东西。
我希望看到整个请求,例如真实的 headers、方法、请求的 body、post 数据等。我知道我可以在代码中看到这些信息,因为我例如在 CURLOPT_HTTPHEADER
中设置它,但我想转储将要发送的“真实”请求(来自 curl)。
最简单的方法是在您的程序中打开 CURLOPT_VERBOSE
。
use WWW::Curl::Easy;
my $curl = WWW::Curl::Easy->new;
$curl->setopt(CURLOPT_HEADER,1);
$curl->setopt(CURLOPT_URL, 'http://example.com');
$curl->setopt(CURLOPT_WRITEDATA,\my $response_body);
# this turns on debugging a la `curl -v http://example.com`
$curl->setopt(CURLOPT_VERBOSE, 1);
my $retcode = $curl->perform;
print("Transfer went ok\n") unless $retcode;
输出:
* Trying 93.184.216.34:80...
* TCP_NODELAY set
* Connected to example.com (93.184.216.34) port 80 (#0)
> GET / HTTP/1.1
Host: example.com
Accept: */*
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Age: 543595
< Cache-Control: max-age=604800
< Content-Type: text/html; charset=UTF-8
< Date: Thu, 25 Nov 2021 14:20:18 GMT
< Etag: "3147526947+gzip"
< Expires: Thu, 02 Dec 2021 14:20:18 GMT
< Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
< Server: ECS (nyb/1D0F)
< Vary: Accept-Encoding
< X-Cache: HIT
< Content-Length: 1256
<
* Connection #0 to host example.com left intact
Transfer went ok
如果你想要更花哨的东西,你必须自己动手。您可以通过将 CURLOPT_DEBUGFUNCTION
设置为 Perl 代码引用来覆盖 CURLOPT_VERBOSE
所做的事情。每行调试输出都会调用它。
签名似乎与 libcurl 文档中的不同,但可以推断出发生了什么。
$curl->setopt(CURLOPT_VERBOSE, 1);
$curl->setopt(CURLOPT_DEBUGFUNCTION, sub {
use Data::Dumper;
print Dumper \@_;
});
此集合的前几行输出如下所示。
[
[0] " Trying 93.184.216.34:80...
",
[1] undef,
[2] 0
]
[
[0] "TCP_NODELAY set
",
[1] undef,
[2] 0
]
[
[0] "Connected to example.com (93.184.216.34) port 80 (#0)
",
[1] undef,
[2] 0
]
[
[0] "GET / HTTP/1.1
Host: example.com
Accept: */*
",
[1] undef,
[2] 2
]
第一个参数似乎是文本。
根据文档,调试数据有几种类型。
typedef enum { CURLINFO_TEXT = 0, CURLINFO_HEADER_IN, /* 1 */ CURLINFO_HEADER_OUT, /* 2 */ CURLINFO_DATA_IN, /* 3 */ CURLINFO_DATA_OUT, /* 4 */ CURLINFO_SSL_DATA_IN, /* 5 */ CURLINFO_SSL_DATA_OUT, /* 6 */ CURLINFO_END } curl_infotype;
鉴于我的最后一个示例有一个 2
并且所有其他示例都有一个 0
作为它们的第三个参数,我们可以假设这一定是类型。
我还没弄明白第二个参数是什么。
这给我们留下了:
$curl->setopt(CURLOPT_DEBUGFUNCTION, sub {
my ($text, undef, $type) = @_;
# ...
});
碰巧,这些类型已被 WWW::Curl::Easy 作为常量导入。所以我们可以做这样的事情来只得到传出的 header.
$curl->setopt(CURLOPT_DEBUGFUNCTION, sub {
my ($text, undef, $type) = @_;
print $text if $type == CURLINFO_HEADER_OUT;
});
这将输出:
$ /usr/bin/perl foo.pl
GET / HTTP/1.1
Host: example.com
Accept: */*
Transfer went ok
传入的 header 似乎一次只有一个,因此您可以过滤。
$curl->setopt(CURLOPT_DEBUGFUNCTION, sub {
my ($text, undef, $type) = @_;
if ($type == CURLINFO_HEADER_IN && $text =~ m/Etag: "(.+)"/) {
print "Etag is \n";
}
});
一个更复杂的例子是获取整个调试输出并将其转换为 HTTP::Request and HTTP::Response objects.
$curl->setopt(CURLOPT_WRITEDATA,$response_body);
$curl->setopt(CURLOPT_VERBOSE, 1);
my ($req, $res);
$curl->setopt(CURLOPT_DEBUGFUNCTION, sub {
my ($text, undef, $type) = @_;
require HTTP::Request;
require HTTP::Response;
if ($type == CURLINFO_HEADER_OUT) {
$req = HTTP::Request->parse($text);
} elsif ($type == CURLINFO_DATA_OUT) {
$req->content($text);
} elsif ($type == CURLINFO_HEADER_IN) {
unless ($res) {
$res = HTTP::Response->parse($text);
$res->request($req);
return 0; # this is retcode
}
# this is from HTTP::Message
# (https://metacpan.org/dist/HTTP-Message/source/lib/HTTP/Message.pm#L60)
my @hdr;
while (1) {
if ($text =~ s/^([^\s:]+)[ \t]*: ?(.*)\n?//) {
push(@hdr, , );
$hdr[-1] =~ s/\r\z//;
}
elsif (@hdr && $text =~ s/^([ \t].*)\n?//) {
$hdr[-1] .= "\n";
$hdr[-1] =~ s/\r\z//;
}
else {
$text =~ s/^\r?\n//;
last;
}
}
$res->header(@hdr) if @hdr;
} elsif ($type == CURLINFO_DATA_IN) {
$res->content($text);
}
return 0; # this is retcode
});
这将为您提供一个 HTTP::Request 和一个 HTTP::Response object,每个都包含所有 header 和内容。不确定这是否有用,但它很好地演示了此功能的可能性。
免责声明:我是 libwww-perl.
的维护者