json - 检查 fetch_json sub 中的 HTTP 代码/保存以前的输出以在 Perl 中进行备份

标签 json perl http curl

所以我必须更新一个 perl 脚本,它会遍历 json 文件,获取名为“items”的键,并将这些项目转换为 perl 输出。

总的来说,我是 Perl/编码方面的菜鸟,所以请耐心等待🥺。 offset 变量在每个 url 被迭代时设置。将一个curl命令传递到终端,将文件放入“@lines”数组中,最后,$data中存储的任何json数据都会被解码和转换。在下面的 block 中(其中 # populate %manager_to_directs、# populate %user_to_management_chain 和 # populate %manager_to_followers 被注释)是 fetch_json 被调用的地方,也是哈希变量从解码的 json 中获取数据的地方。 (***如果我错误地解释了此代码,请随时纠正我)

存在一个问题,即每次执行该程序时 $cmd 都不考虑 HTTP 响应。我只希望当且仅当程序获得http 200(OK)或http 204(NO_CONTENT)时才处理结果,因为程序将运行并且有时会部分刷新我们的json端点(下面终端的curl命令输出中的url),或者有时甚至根本不刷新。

我所假设的是,我可能必须导入 HTTP::Response pragma 并以某种方式将其从 fetch_json 中运行的命令中提取出来,但我没有其他线索从那里开始。

我是否必须更新 $cmd 才能提取 http 代码?如果是这样,如果收到 200 或 204 以外的任何内容,我将如何在 fetch_json 子中解释它以退出进程?

哦,还有,我如何将上次执行的输出保存在备份文件中?

如果我能在这里得到任何帮助,我将不胜感激!

参见下面的代码:


从测试运行中提取此内容:

curl -o filename -w "HTTP CODE: %{http_code}\n"   --insecure       --key <YOUR KEY>    --cert <YOUR CERT>   https://xxxxxxxxxx-xxxxxx-xxxx.xxx.xxxxxxxxxx.com:443/api/v1/reports/active/week > http.out

#!/usr/bin/env perl

use warnings;
use strict;
use JSON qw(decode_json);
use autodie qw(open close chmod unlink);
use File::Basename;
use File::Path qw(make_path rmtree);
use Cwd qw(abs_path);
use Data::Dumper;
use feature qw(state);


sub get_fetched_dir {
    return "$ENV{HOME}/tmp/mule_user_fetched";
}


# fetch from mulesoft server and save local copy
sub fetch_json {
    state $now = time();
    my ($url) = @_;
    my $dir = get_fetched_dir();
    if (!-e $dir) {
        make_path($dir);
        chmod 0700, $dir;
    }

    my ($offset) = $url =~ m{offset=(\d+)};
    if (!defined $offset) {
        $offset = 0;
    }
    $offset = sprintf ("%03d", $offset);

    my $filename = "$dir/offset${offset}.json";
    print "$filename\n";
    my @fields = stat $filename;
    my $size = $fields[7];
    my $mtime = $fields[9];
    if (!$size || !$mtime || $now-$mtime > 24*60*60) {
        my $cmd = qq(curl \\
--insecure \\
--silent \\
--key $ENV{KEY} \\
--cert $ENV{CERT} \\
$url > $filename
);
        #print $cmd;
        system($cmd);
        chmod 0700, $filename;
    }
    open my $fh, "<", $filename;
    my @lines = <$fh>;
    close $fh;
    return undef if !@lines;
    my $data;
    eval {
        $data = decode_json (join('',@lines));
    };
    if ($@) {
        unlink $filename;
        print "Bad JSON detected in $filename.\n";
        print "I have deleted $filename.\n";
        print "Please re-run script.\n";
        exit(1);
    }
    return $data;
}

die "Usage:\n KEY=key_file CERT=cert_file mule_to_jira.pl\n"
if !defined $ENV{KEY} || !defined $ENV{CERT};
print "fetching data from mulesoft\n";


# populate %manager_to_directs
my %manager_to_directs;
my %user_to_manager;
my @users;
my $url = "https://enterprise-worker-data.eip.vzbuilders.com/api/v1/reports/active/week";
while ($url && $url ne "Null") {
    my $data = fetch_json($url);
    last if !defined $data;
    $url = $data->{next};
    #print $url;
    my $items = $data->{items};
    foreach my $item (@$items) {
        my $shortId = $item->{shortId};
        my $manager = $item->{organization}{manager};
        push @users, $shortId;
        next if !$manager;
        $user_to_manager{$shortId} = $manager;
        push @{$manager_to_directs{$manager}}, $shortId;
    }
}


# populate %user_to_management_chain
# populate %manager_to_followers
my %user_to_management_chain;
my %manager_to_followers;
foreach my $user (keys %user_to_manager) {
    my $manager = $user_to_manager{$user};
    my $prev = $user;
    while ($manager && $prev ne $manager) {
        push @{$manager_to_followers{$manager}}, $user;
        push @{$user_to_management_chain{$user}}, $manager;
        $prev = $manager;
        $manager = $user_to_manager{$manager};  # manager's manager
    }
}


# write backyard.txt
open my $backyard_fh, ">", "backyard.txt";
foreach my $user (sort keys %user_to_management_chain) {
    my $chain = join ',', @{$user_to_management_chain{$user}};
    print $backyard_fh "$user:$chain\n";
}
close $backyard_fh;


# write teams.txt
open my $team_fh, ">", "teams.txt";
foreach my $user (sort @users) {
    my $followers = $manager_to_followers{$user};
    my $followers_joined = $followers ? join (',', sort @$followers) : "";
    print $team_fh "$user:$followers_joined\n";
}
close $team_fh;


my $dir = get_fetched_dir();
rmtree $dir, {safe => 1};

最佳答案

因此,如果您希望保持 Web 获取和 Perl 处理解耦,您可以修改 curl 命令,以便通过添加 -i 在输出中包含响应 header 选项。这意味着必须修改 Perl 才能在到达正文之前读取和处理 header 。成功的 http.out 看起来像这样:

HTTP/1.1 200 OK
Server: somedomain.com
Date: <date retrieved>
Content-Type: application/json; charset=utf-8
Content-Length: <size of JSON>
Status: 200 OK
Maybe: More Headers
Blank: Line signals start of body

{
    JSON object here
}

不成功的 curl 将在 HTTP/1.1 旁边的第一行显示 200 OK 以外的内容,因此您可以判断出了问题。

或者,您可以让 Perl 执行实际的 HTTP 获取,而不是依赖于curl;您可以使用LWP::UserAgent或 Perl 中的任何其他 HTTP 客户端库,它将为您提供整个响应,而不仅仅是正文。

关于json - 检查 fetch_json sub 中的 HTTP 代码/保存以前的输出以在 Perl 中进行备份,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61925598/

相关文章:

c# - 使用 HttpListener 自定义 404

python - 如何将包含字典列表的 JSON 文件读取到 pandas 数据框中?

javascript - JSON数组在DOM中显示未定义和jquery中的数据

java - 从 Java 中的一个大 JSON 中仅提取一行

javascript - 从json中获取特定信息

perl - 为 Dist::Zilla 类型转换模块编写测试

perl - Perl 的模板工具包可以警告未定义的值吗?

string - Perl:将字符串转换为 Unicode

javascript - Angular Http 参数未发送

java - 使用 Apache HttpClient 发布 MultipartEntity 时,ByteArrayBody 可以工作,但 InputStreamBody 会抛出 NoHttpResponseException