POST 使用 Perl 请求并在 dancer 路由中读取响应对象
POST request with Perl and read response object within dancer route
尝试用 perl 编写以下内容的确切等价物:
curl -H "Content-Type: application/json" -X POST -d '{"user": { "uid":"13453"},"access_token":"3428D3194353750548196BA3FD83E58474E26B8B9"}' https://platform.gethealth.io/v1/health/account/user/
没有使用 perl 的经验,这是我尝试过的:
use HTTP::Request::Common;
use LWP::UserAgent;
get '/gethealthadduser/:id' => sub {
my $ua = LWP::UserAgent->new;
$ua->request(POST 'https://platform.gethealth.io/v1/health/account/user', [{"user": { "uid":param("id")},"access_token":config->{gethealthtoken}}]);
};
我认为您已经在使用 Dancer,或者您正在向现有应用程序添加一些东西,目标是将 POST 请求隐藏到 API 后面的另一个服务。
在您的 curl 示例中,您有 Content-Type application/json
,但在您的 Perl 代码中,您发送的是一个表单。这很可能是 Content-Type application/x-www-form-urlencoded
。这可能不是服务器想要的。
除此之外,您将表单数据作为数组引用传递,这让 POST
相信它们是 header。那不是你想要的。
为了完成与 curl 相同的操作,您还需要几个步骤。
- 您需要将数据转换为 JSON。幸运的是 Dancer 带来了 a nice DSL keyword
to_json
可以轻松做到这一点。
- 你需要告诉LWP::UserAgent使用右边的Content-Typeheader。那是
application/json
,您可以在请求级别设置它,或者作为用户代理 object 的默认设置。我会做前者。
- 除此之外,我建议不要使用 HTTP::Request::Common 将关键字导入 Dancer 应用程序。
GET
和 POST
等等是 upper-case 而 Dancer DSL 有 get
和 post
即 lower-case,但它仍然令人困惑。明确地使用 HTTP::Request 代替。
这是最后一件事。
use LWP::UserAgent;
use HTTP::Request;
get '/gethealthadduser/:id' => sub {
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new(
POST => 'https://platform.gethealth.io/v1/health/account/user',
[ 'Content-Type' => 'application/json' ], # headers
to_json { user => param("id"), access_token => config->{gethealthtoken} }, # content
);
my $res = $ua->request($req);
# log the call with log level debug
debug sprintf( 'Posted to gethealth.io with user %s and got a %s back.',
param('id'),
$res->status_line
);
# do things with $res
};
尝试使用 HTTP::Tiny(它在 CPAN 上)。恕我直言,它比 LWP::UserAgent 更简洁,尽管后者更受欢迎。
下面是一些开箱即用的代码:
use HTTP::Tiny 0.064; # use a recent version or better
my $url = 'https://api.somewhere.com/api/users';
my $data = {
first_name => "joe",
last_name => "blow"
};
my $method = 'POST';
my $default_headers = {
'Authorization' => "Bearer ".$token, # if needed
'Accept' => 'application/json'
};
my $tiny = HTTP::Tiny->new(
agent => 'mywebsite.com',
default_headers => $default_headers,
timeout => 30
);
my $response;
if ( ($method eq 'POST') || ($method eq 'PUT') ) {
$response = $tiny->request($method, $url, {
headers => {
'Content-Type' => 'application/json'
},
content => &toJSON($data)
});
}
else {
if ($data) {
die "data cannot be included with method $method";
}
$response = $tiny->request($method, $url);
}
die unless $response->{'success'};
祝你项目顺利!
以下是已发布参数格式和结构正确的解决方案:
get '/api/gethealthadduser/:id' => sub {
my %user = (
uid => param("id")
);
# my $user = {
# uid => param("id")
# };
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new(
POST => 'https://platform.gethealth.io/v1/health/account/user/',
[ 'Content-Type' => 'application/json' ], # headers
JSON::to_json({ user => \%user, access_token => config->{gethealthtoken} }) # content
);
my $res = $ua->request($req);
print STDERR Dumper($res);
$res;
};
尝试用 perl 编写以下内容的确切等价物:
curl -H "Content-Type: application/json" -X POST -d '{"user": { "uid":"13453"},"access_token":"3428D3194353750548196BA3FD83E58474E26B8B9"}' https://platform.gethealth.io/v1/health/account/user/
没有使用 perl 的经验,这是我尝试过的:
use HTTP::Request::Common;
use LWP::UserAgent;
get '/gethealthadduser/:id' => sub {
my $ua = LWP::UserAgent->new;
$ua->request(POST 'https://platform.gethealth.io/v1/health/account/user', [{"user": { "uid":param("id")},"access_token":config->{gethealthtoken}}]);
};
我认为您已经在使用 Dancer,或者您正在向现有应用程序添加一些东西,目标是将 POST 请求隐藏到 API 后面的另一个服务。
在您的 curl 示例中,您有 Content-Type application/json
,但在您的 Perl 代码中,您发送的是一个表单。这很可能是 Content-Type application/x-www-form-urlencoded
。这可能不是服务器想要的。
除此之外,您将表单数据作为数组引用传递,这让 POST
相信它们是 header。那不是你想要的。
为了完成与 curl 相同的操作,您还需要几个步骤。
- 您需要将数据转换为 JSON。幸运的是 Dancer 带来了 a nice DSL keyword
to_json
可以轻松做到这一点。 - 你需要告诉LWP::UserAgent使用右边的Content-Typeheader。那是
application/json
,您可以在请求级别设置它,或者作为用户代理 object 的默认设置。我会做前者。 - 除此之外,我建议不要使用 HTTP::Request::Common 将关键字导入 Dancer 应用程序。
GET
和POST
等等是 upper-case 而 Dancer DSL 有get
和post
即 lower-case,但它仍然令人困惑。明确地使用 HTTP::Request 代替。
这是最后一件事。
use LWP::UserAgent;
use HTTP::Request;
get '/gethealthadduser/:id' => sub {
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new(
POST => 'https://platform.gethealth.io/v1/health/account/user',
[ 'Content-Type' => 'application/json' ], # headers
to_json { user => param("id"), access_token => config->{gethealthtoken} }, # content
);
my $res = $ua->request($req);
# log the call with log level debug
debug sprintf( 'Posted to gethealth.io with user %s and got a %s back.',
param('id'),
$res->status_line
);
# do things with $res
};
尝试使用 HTTP::Tiny(它在 CPAN 上)。恕我直言,它比 LWP::UserAgent 更简洁,尽管后者更受欢迎。
下面是一些开箱即用的代码:
use HTTP::Tiny 0.064; # use a recent version or better
my $url = 'https://api.somewhere.com/api/users';
my $data = {
first_name => "joe",
last_name => "blow"
};
my $method = 'POST';
my $default_headers = {
'Authorization' => "Bearer ".$token, # if needed
'Accept' => 'application/json'
};
my $tiny = HTTP::Tiny->new(
agent => 'mywebsite.com',
default_headers => $default_headers,
timeout => 30
);
my $response;
if ( ($method eq 'POST') || ($method eq 'PUT') ) {
$response = $tiny->request($method, $url, {
headers => {
'Content-Type' => 'application/json'
},
content => &toJSON($data)
});
}
else {
if ($data) {
die "data cannot be included with method $method";
}
$response = $tiny->request($method, $url);
}
die unless $response->{'success'};
祝你项目顺利!
以下是已发布参数格式和结构正确的解决方案:
get '/api/gethealthadduser/:id' => sub {
my %user = (
uid => param("id")
);
# my $user = {
# uid => param("id")
# };
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new(
POST => 'https://platform.gethealth.io/v1/health/account/user/',
[ 'Content-Type' => 'application/json' ], # headers
JSON::to_json({ user => \%user, access_token => config->{gethealthtoken} }) # content
);
my $res = $ua->request($req);
print STDERR Dumper($res);
$res;
};