Python处理AWS Kinesis+Lambda CLI事件报UnicodeDecodeError排查
问题背景
已部署开启服务端加密的AWS Kinesis数据流,关联Lambda函数负责事件处理。通过CLI调用put-record接口写入JSON格式测试事件时,Lambda端解析逻辑抛出如下错误:UnicodeDecodeError: 'utf-8' codec can't decode byte 0x99 in position 0: invalid start byte
该配置此前已正常运行数月,未做任何代码变更的情况下约1个月前突然出现该问题。
复现信息
事件写入CLI命令
aws kinesis put-record \ --stream-name "dev" \ --partition-key "user_event" \ --data ' [{ "user_id": 2002, "group_id": 2002, "created_at": "2021-11-24T16:03:03Z", "user_event_id": 989898989898, "event_type": "in", "event_date": "2022-11-03T14:03:03Z", "category": "music", "is_free": true }]' \ --profile dev \ --region eu-central-1
Lambda解析代码
for record in kinesis_data["Records"]: partition_key = record["kinesis"]["partitionKey"] if not self.accepted_parsers(partition_key): continue encoded_data = record["kinesis"]["data"] payload_string = base64.b64decode(encoded_data) payload = json.loads(payload_string)
错误栈信息
[ERROR] UnicodeDecodeError: 'utf-8' codec can't decode byte 0x99 in position 0: invalid start byte Traceback (most recent call last): File "/var/task/events_processing.py", line 38, in lambda_handler status_code = lambda_interactor.call(event) File "/var/task/lib/lambda_interactor.py", line 113, in call event_dicts = self.kinesis_parser.call(payload) File "/var/task/lib/kinesis_parser.py", line 22, in call payload = json.loads(payload_string) File "/var/lang/lib/python3.8/json/__init__.py", line 343, in loads s = s.decode(detect_encoding(s), 'surrogatepass')
调试观测结果
- 获取到的
encoded_data丢失了所有JSON格式特殊符号(括号、引号、冒号、逗号、空白符等),仅保留字符串与数字拼接内容 - base64解码后的
payload_string为乱码二进制数据
根因分析
问题出在AWS CLI对二进制参数--data的处理逻辑变更,和Kinesis服务端加密、Lambda逻辑无关:
- Kinesis的
put-record接口要求Data字段传输base64编码后的二进制内容。 - AWS CLI存在
cli-binary-format配置项控制二进制参数的处理逻辑:- 当值为
raw-in-base64-out时,CLI会自动将传入的原始文本/二进制内容做base64编码后提交给接口,符合旧版本CLI的默认行为 - 当值为
base64时,CLI会默认传入的内容已经是base64编码串,会自动过滤所有不在base64合法字符集(A-Za-z0-9+/=)内的字符后直接提交给接口
- 当值为
- 传入的格式化JSON包含大量非base64合法字符(换行、空格、括号、引号、冒号、逗号),被CLI过滤后仅剩下字母数字拼接的无效base64串,存入Kinesis。Lambda拿到该无效串做base64解码后自然得到乱码,触发UTF-8解码错误。
- 故障突然出现的原因是本地AWS CLI自动更新、或配置文件被修改,导致
cli-binary-format的默认值从raw-in-base64-out变为了base64。
修复方案
二选一即可:
- 调用CLI时显式指定二进制格式参数,强制CLI自动编码原始内容,和原有行为保持一致:
在put-record命令中加入参数--cli-binary-format raw-in-base64-out即可。建议同时将传入的JSON压缩为无多余空白的单行字符串,避免不同shell对多行字符串的处理差异。
修复后的命令示例:aws kinesis put-record \ --stream-name "dev" \ --partition-key "user_event" \ --cli-binary-format raw-in-base64-out \ --data '[{"user_id":2002,"group_id":2002,"created_at":"2021-11-24T16:03:03Z","user_event_id":989898989898,"event_type":"in","event_date":"2022-11-03T14:03:03Z","category":"music","is_free":true}]' \ --profile dev \ --region eu-central-1 - 提前将待写入的JSON内容手动做base64编码,再将编码后的字符串传给
--data参数,适配CLI默认的base64输入要求。
如果需要永久修复,可以在AWS CLI配置文件(~/.aws/config)的对应profile下加入如下配置,避免后续其他命令出现同类问题:
cli_binary_format = raw-in-base64-out
内容的提问来源于stack exchange,提问作者qalis
相关产品推荐
相关产品推荐

