You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

REST API POST请求JSON序列化失败问题求助

解决REST API POST请求的反序列化异常问题

问题背景

有位开发者在通过Python的requests库提交POST请求到Traccar的REST API时遇到了反序列化异常,相关代码和报错信息如下:

原执行代码

def Actions(self, imei, name):
    global addAttribute
    if addAttribute == True:
        attributes = {"decoder.timezone":"Etc/GMT"}
    else:
        attributes = ""
    url = "https://example.com/api/devices/"
    data = {"name":name, "uniqueId":imei, "attributes":attributes}
    print("data not transformed:")
    print(data)
    print()
    data_json = json.dumps(data)
    print("data transformed by json.dumps():")
    print(data_json)
    print()
    test = requests.post(url, auth=('mylogin', 'pwd'), json=data_json)
    print(test.content)

控制台报错输出

data not transformed: {'name': 'Example 1', 'uniqueId': 'Example 1', 'attributes': {'decoder.timezone': 'Etc/GMT'}}
data transformed by json.dumps(): {"name": "Example 1", "uniqueId": "Example 1", "attributes": {"decoder.timezone": "Etc/GMT"}}
b'Cannot construct instance of `org.traccar.model.Device` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value (\'{"name": "Example 1", "uniqueId": "Example 1", "attributes": {"decoder.timezone": "Etc/GMT"}}\')\n at [Source: (org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream); line: 1, column: 1]'

问题根源

这个错误其实很典型,核心问题出在requests.post的参数使用上:

  • requests库的json参数接受的是Python字典对象,它会自动帮你完成JSON序列化,同时设置Content-Type: application/json请求头。
  • 但你提前用json.dumps()把字典转成了JSON字符串,再传给json参数,这就导致requests把这个字符串当成了普通数据再次序列化,服务器收到的是一个包裹着JSON字符串的字符串,而非预期的JSON对象,所以Traccar后端的Jackson序列化器无法将其解析成Device实体类。

另外还有个小坑:当addAttribute为False时,你给attributes赋值了空字符串"",但API预期的attributes应该是一个对象(字典)或null,空字符串会引发另一个序列化错误。

修正后的代码

直接去掉手动序列化的步骤,把Python字典传给json参数即可,同时修正attributes的默认值:

import json
import requests

def Actions(self, imei, name):
    global addAttribute
    if addAttribute:  # 简化写法,无需写==True
        attributes = {"decoder.timezone":"Etc/GMT"}
    else:
        attributes = {}  # 或者用None,根据API文档选择合适的默认值
    url = "https://example.com/api/devices/"
    data = {"name":name, "uniqueId":imei, "attributes":attributes}
    print("data to be sent:")
    print(data)
    print()
    # 直接传字典给json参数,requests自动处理序列化和请求头
    test = requests.post(url, auth=('mylogin', 'pwd'), json=data)
    print(test.content)

补充方案(不推荐但可了解)

如果你非要手动做JSON序列化,那应该用data参数传递序列化后的字符串,同时手动设置请求头:

data_json = json.dumps(data)
headers = {"Content-Type": "application/json"}
test = requests.post(url, auth=('mylogin', 'pwd'), data=data_json, headers=headers)

但显然直接用json=data更简洁,也不容易出错。

另外,如果API允许attributes字段缺失,也可以在addAttribute为False时不把attributes键加入data字典,这样更符合REST API的规范。

内容的提问来源于stack exchange,提问作者xtl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:24:08