Perl v5.36.0调用S3分片API时PartNumber转字符串问题求助
使用Perl v5.36.0脚本调用AWS S3分片上传API,完成分片上传后,Data::Dumper输出的哈希中PartNumber为整数类型,但通过encode_json将哈希序列化为JSON并写入文件后,所有PartNumber被转为字符串,导致complete-multipart-upload API调用失败,错误提示参数类型不匹配(要求整数,实际为字符串)。
相关代码片段
分片上传并构建Part信息的代码:
my $part_no = 1; my %final_upload_file; my @multi_part_hash; foreach my $temp_file (@split_files) { my $tota_no_parts= @split_files; my $upload_part = "aws s3api upload-part --bucket <s3_bucket_name> --key ".$filename." --part-number ".$part_no." --body ".$temp_file." --upload-id ".$UploadId; $temp_json=`$upload_part`; my %upload_response = %{decode_json $temp_json}; my $eTag = $upload_response{'ETag'}; my %temp_part_hash; $temp_part_hash{'PartNumber'} = int($part_no); $temp_part_hash{'ETag'} = $eTag; push @multi_part_hash, \%temp_part_hash; if( $part_no le $tota_no_parts) { $part_no++; } } my %final_hash; $final_hash{'Parts'} = \@multi_part_hash; print Dumper(\%final_hash);
序列化JSON的代码:
my $json_text = encode_json \%final_hash; print("\$json_text: $json_text\n"); my $json_filename = 'test.json'; open(FH, '>', $json_filename) or die $!; print FH $json_text; close(FH);
使用的模块:
use strict; use FileHandle; use Getopt::Long; use POSIX; use Data::Dumper; use feature q(say); use JSON;
现象与错误
Data::Dumper输出的PartNumber为整数:
$VAR1 = {
'Parts' => [
{
'PartNumber' => 1,
'ETag' => '"46f438ba2afd8d6dc03958b867a349b1"'
},
...(其余分片信息)
]
};
- 序列化后的JSON中
PartNumber为字符串:
$json_text:
{"Parts":[{"PartNumber":"1","ETag":""46f438ba2afd8d6dc03958b867a349b1""},{"ETag":""7b1e03e9ed7bb49d907e5a2d25b89159""},{"PartNumber":"2"},...]}
- API调用错误信息:
Parameter validation failed: Invalid type for parameter
MultipartUpload.Parts[0].PartNumber, value: 1, type: <class 'str'>,
valid types: <class 'int'>
...(其余分片的相同错误)
问题根源是Perl弱类型特性导致JSON模块序列化时无法准确识别数字类型,以下是几种可靠的修复方式:
1. 替换为JSON::XS模块
JSON::XS是更严谨的JSON序列化模块,对Perl变量的类型识别更准确,能确保整数被序列化为JSON数字类型:
# 替换原有的use JSON;为 use JSON::XS; # 序列化代码无需修改 my $json_text = encode_json \%final_hash;
2. 启用核心JSON模块的convert_blessed选项
如果坚持使用Perl核心的JSON模块,可以通过启用convert_blessed选项来优化类型识别:
use JSON; # 创建JSON对象并启用选项 my $json_serializer = JSON->new->convert_blessed; my $json_text = $json_serializer->encode(\%final_hash);
3. 强制将PartNumber转为数字类型
Perl中可以通过数字上下文强制变量转为数字类型,确保内部标记为数字,让JSON模块正确序列化:
# 在构建Part信息时,将int($part_no)替换为0+$part_no $temp_part_hash{'PartNumber'} = 0 + $part_no;
0+$part_no会强制变量进入数字上下文,将其内部类型标记为数字,序列化时就会输出为无引号的JSON数字。
内容的提问来源于stack exchange,提问作者Rito Sarkar

