处理嵌套JSON字符串的正确姿势:避免二次转义与多层解析

处理嵌套json字符串的正确姿势:避免二次转义与多层解析

在处理包含已编码JSON字符串的字典时,直接对外部字典进行JSON序列化会导致内部字符串的引号被二次转义。本文将深入探讨这一常见问题,解释其发生机制,并提供一种清晰的两步解码策略,确保消费者能够正确解析嵌套的JSON数据,尤其适用于消息队列中payload字段被定义为字符串的场景。

理解JSON序列化中的嵌套字符串问题

在数据传输和存储中,我们经常需要将复杂的数据结构序列化为JSON字符串。一个常见场景是,一个字典中的某个字段本身包含一个已经编码好的JSON字符串。当尝试将这个外部字典再次序列化时,就会遇到内部JSON字符串被“二次转义”的问题。

考虑以下场景:我们有一个消息体 message,它是一个Python字典,需要根据Avro schema将其序列化为JSON字符串。

import jsonfrom datetime import datetimefrom io import StringIOimport fastavro# 原始消息字典message = {    "name": "any",    "ingestion_ts": datetime.utcnow(),    "values": {        "amount": 5,        "countries": ["se", "nl"],        "source": {            "name": "web",            "url": "whatever"        }    }}# 假设 avro_schema 已定义avro_schema = {  "type": "record",  "name": "MyMessage",  "fields": [    {"name": "name", "type": "string"},    {"name": "ingestion_ts", "type": {"type": "long", "logicalType": "timestamp-micros"}},    {"name": "values", "type": {      "type": "record",      "name": "Values",      "fields": [        {"name": "amount", "type": "int"},        {"name": "countries", "type": {"type": "array", "items": "string"}},        {"name": "source", "type": {          "type": "record",          "name": "Source",          "fields": [            {"name": "name", "type": "string"},            {"name": "url", "type": "string"}          ]        }}      ]    }}  ]}# 使用 fastavro 将 message 序列化为 JSON 字符串fo = StringIO()fastavro.json_writer(fo, avro_schema, [message])message_str = fo.getvalue()print(f"内部 JSON 字符串: {message_str}")# 示例输出: '{"name": "any", "ingestion_ts": 1703192665965373, "values": {"amount": 5, "countries": ["se", "nl"], "source": {"name": "web", "url": "whatever"}}}'

现在,这个 message_str 需要被包装到一个更大的字典 wrap 中,作为其 payload 字段的值,然后发送到消息队列。消息队列期望的外部Schema如下:

{  "type": "record",  "namespace": "CDCEvent",  "name": "CDCEvent",  "fields": [    {"doc": "The system that generated the event", "type": "string", "name": "sys"},    {"doc": "The operation performed on the event", "type": "string", "name": "op"},    {"doc": "The content of the event", "type": "string", "name": "payload"}  ]}

注意,payload 字段的类型被定义为 string。这意味着 payload 字段的值在外部JSON中必须是一个普通的字符串。

如果我们直接将 message_str 赋值给 wrap 字典的 payload 字段,并再次使用 json.dumps 进行序列化:

wrap = {    "sys": "my_system",    "op": "c",    "payload": message_str}wrap_str = json.dumps(wrap)print(f"二次序列化后的 JSON 字符串: {wrap_str}")# 示例输出: '{"sys": "my_system", "op": "c", "payload": "{"name": "any", "ingestion_ts": 1703192665965373, "values": {"amount": 5, "countries": ["se", "nl"], "source": {"name": "web", "url": "whatever"}}}"}'

可以看到,payload 字段中的双引号都被反斜杠 转义了。这是因为 json.dumps 在处理 wrap 字典时,将 message_str 视为一个普通的Python字符串值。为了确保生成的外部JSON字符串是合法的,它必须对 message_str 内部的所有特殊字符(如双引号)进行转义。这并非错误,而是 json.dumps 按照JSON规范正确地序列化一个包含字符串值的字段。

Find JSON Path Online Find JSON Path Online

Easily find JSON paths within JSON objects using our intuitive Json Path Finder

Find JSON Path Online 30 查看详情 Find JSON Path Online

消费者端的正确解析策略

问题的核心不在于生产者端的“二次编码”错误,而在于消费者端如何正确地“二次解码”。如果消费者直接尝试将 wrap_str 整体作为一个JSON对象进行单次解析,并期望 payload 字段的值是一个可以直接使用的JSON对象,那么就会失败,因为它得到的是一个包含转义字符的字符串。

正确的解析方法是采用两步解码策略:

解析外部JSON字符串: 首先,将接收到的 wrap_str 使用 json.loads() 解析成一个Python字典 wrapped_object。解析内部JSON字符串: 从 wrapped_object 中取出 payload 字段的值,这个值现在是一个普通的Python字符串,其中包含了原始的JSON数据(没有转义)。然后,再对这个 payload 字符串进行一次JSON解析。

以下是消费者端的示例代码:

# 假设消费者接收到 wrap_strreceived_wrap_str = '{"sys": "my_system", "op": "c", "payload": "{"name": "any", "ingestion_ts": 1703192665965373, "values": {"amount": 5, "countries": ["se", "nl"], "source": {"name": "web", "url": "whatever"}}}"}'# 第一步:解析外部 JSONwrapped_object = json.loads(received_wrap_str)print(f"第一步解析结果 (Python 字典): {wrapped_object}")# 此时 wrapped_object['payload'] 的值是一个不含转义符的字符串:# '{"name": "any", "ingestion_ts": 1703192665965373, "values": {"amount": 5, "countries": ["se", "nl"], "source": {"name": "web", "url": "whatever"}}}'# 第二步:解析 payload 字段中的内部 JSON 字符串payload_json_str = wrapped_object["payload"]print(f"从 payload 字段中取出的 JSON 字符串: {payload_json_str}")# 根据原始内部 Avro Schema 进行解析# 注意:这里需要再次提供内部消息的 avro_schemainner_message_stream = StringIO(payload_json_str)decoded_messages = []for record in fastavro.json_reader(inner_message_stream, avro_schema):    decoded_messages.append(record)print(f"第二步解析结果 (原始消息列表): {decoded_messages}")# 示例输出: [{'name': 'any', 'ingestion_ts': 1703192665965373, 'values': {'amount': 5, 'countries': ['se', 'nl'], 'source': {'name': 'web', 'url': 'whatever'}}}]

通过这种两步解析方法,消费者能够成功地从 wrap_str 中提取出原始的 message 数据。

注意事项与最佳实践

Schema一致性: 这种方法依赖于 payload 字段在外部Schema中被明确定义为 string 类型。如果外部Schema允许 payload 是一个JSON对象,那么在生产者端就应该直接将原始字典 message 赋值给 payload,而不是先将其序列化为字符串。

# 如果外部 Schema 允许 payload 是一个 JSON 对象# 那么生产者端可以直接这样处理,避免预先序列化# wrap = {#     "sys": "my_system",#     "op": "c",#     "payload": message # 直接放置字典,而不是字符串# }# wrap_str = json.dumps(wrap) # json.dumps 会自动处理嵌套字典

在这种情况下,消费者端只需要一步 json.loads(wrap_str) 即可。

性能考量: 两次JSON解析会带来一定的性能开销。在对性能要求极高的场景下,如果设计允许,尽量避免这种嵌套字符串的设计。清晰的文档: 务必在系统设计文档中明确指出 payload 字段的特殊性,以及消费者需要执行两步解析的流程,以避免混淆和错误。错误处理: 在实际应用中,解析 payload_json_str 时应加入 try-except 块来处理可能的 json.JSONDecodeError,以应对 payload 内容不符合JSON格式的情况。

总结

当一个字典的字段被明确要求存储一个已经编码的JSON字符串时,对其进行外部JSON序列化是会产生内部引号转义的。这并非错误,而是标准JSON序列化行为。解决之道在于消费者端采用两步解码策略:首先解析外部JSON以获取包含内部JSON字符串的字段值,然后再次解析该字符串以恢复原始数据。理解这一机制对于构建健壮的数据处理管道至关重要。

以上就是处理嵌套JSON字符串的正确姿势:避免二次转义与多层解析的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/569404.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月10日 05:09:46
下一篇 2025年11月10日 05:20:25

相关推荐

  • 如何解决本地图片在使用 mask JS 库时出现的跨域错误?

    如何跨越localhost使用本地图片? 问题: 在本地使用mask js库时,引入本地图片会报跨域错误。 解决方案: 要解决此问题,需要使用本地服务器启动文件,以http或https协议访问图片,而不是使用file://协议。例如: python -m http.server 8000 然后,可以…

    2025年12月24日
    200
  • 使用 Mask 导入本地图片时,如何解决跨域问题?

    跨域疑难:如何解决 mask 引入本地图片产生的跨域问题? 在使用 mask 导入本地图片时,你可能会遇到令人沮丧的跨域错误。为什么会出现跨域问题呢?让我们深入了解一下: mask 框架假设你以 http(s) 协议加载你的 html 文件,而当使用 file:// 协议打开本地文件时,就会产生跨域…

    2025年12月24日
    200
  • 正则表达式在文本验证中的常见问题有哪些?

    正则表达式助力文本输入验证 在文本输入框的验证中,经常遇到需要限定输入内容的情况。例如,输入框只能输入整数,第一位可以为负号。对于不会使用正则表达式的人来说,这可能是个难题。下面我们将提供三种正则表达式,分别满足不同的验证要求。 1. 可选负号,任意数量数字 如果输入框中允许第一位为负号,后面可输入…

    2025年12月24日
    000
  • 为什么多年的经验让我选择全栈而不是平均栈

    在全栈和平均栈开发方面工作了 6 年多,我可以告诉您,虽然这两种方法都是流行且有效的方法,但它们满足不同的需求,并且有自己的优点和缺点。这两个堆栈都可以帮助您创建 Web 应用程序,但它们的实现方式却截然不同。如果您在两者之间难以选择,我希望我在两者之间的经验能给您一些有用的见解。 在这篇文章中,我…

    2025年12月24日
    000
  • 姜戈顺风

    本教程演示如何在新项目中从头开始配置 django 和 tailwindcss。 django 设置 创建一个名为 .venv 的新虚拟环境。 # windows$ python -m venv .venv$ .venvscriptsactivate.ps1(.venv) $# macos/linu…

    2025年12月24日
    000
  • 花 $o 学习这些编程语言或免费

    → Python → JavaScript → Java → C# → 红宝石 → 斯威夫特 → 科特林 → C++ → PHP → 出发 → R → 打字稿 []https://x.com/e_opore/status/1811567830594388315?t=_j4nncuiy2wfbm7ic…

    2025年12月24日
    000
  • 揭示绝对定位的缺点并提出解决方案:常见问题的规避策略

    绝对定位的弊端揭秘:如何避免常见问题? 绝对定位是网页设计中常用的一种布局方式,它可以让元素精确地定位在页面上的指定位置。然而,尽管绝对定位在某些情况下非常有用,但它也存在一些弊端。本文将揭示绝对定位的弊端,并提供一些方法来避免常见问题。 首先,绝对定位的一个弊端是元素定位可能受到浏览器窗口大小的影…

    2025年12月24日
    000
  • 常见问题和解决方法:绝对定位运动指令的疑问与解答

    绝对定位运动指令的常见问题及解决方法 摘要:随着技术的不断进步,绝对定位运动在现代机械设备中得到了广泛应用。然而,在使用绝对定位运动指令的过程中,常常会遇到各种问题。本文将重点讨论常见的绝对定位运动指令问题,并提供相应的解决方法和具体的代码示例。 一、绝对定位运动指令简介绝对定位运动指令是指根据目标…

    2025年12月24日
    000
  • 揭秘绝对定位故障:常见问题和解决方法曝光

    绝对定位故障大揭秘:常见问题及解决方案 引言: 绝对定位(Absolute positioning)是CSS中常用的一种定位方式,它允许开发者将元素精确地放置在一个给定的位置上。然而,由于其特殊的性质和较为复杂的用法,绝对定位经常会出现各种问题。本文将揭示绝对定位的常见故障,并提供相应的解决方案,同…

    2025年12月24日
    000
  • 深入理解CSS框架与JS之间的关系

    深入理解CSS框架与JS之间的关系 在现代web开发中,CSS框架和JavaScript (JS) 是两个常用的工具。CSS框架通过提供一系列样式和布局选项,可以帮助我们快速构建美观的网页。而JS则提供了一套功能强大的脚本语言,可以为网页添加交互和动态效果。本文将深入探讨CSS框架和JS之间的关系,…

    2025年12月24日
    000
  • 详解Css Flex 弹性布局中的常见问题及解决方案

    详解CSS Flex弹性布局中的常见问题及解决方案 引言:CSS Flex弹性布局是一种现代的布局方式,其具有优雅简洁的语法和强大的灵活性,广泛应用于构建响应式的web页面。然而,在实际应用中,经常会遇到一些常见的问题,如元素排列不如预期、尺寸不一致等。本文将详细介绍这些问题,并提供相应的解决方案,…

    2025年12月24日
    200
  • HTML+CSS+JS实现雪花飘扬(代码分享)

    使用html+css+js如何实现下雪特效?下面本篇文章给大家分享一个html+css+js实现雪花飘扬的示例,希望对大家有所帮助。 很多南方的小伙伴可能没怎么见过或者从来没见过下雪,今天我给大家带来一个小Demo,模拟了下雪场景,首先让我们看一下运行效果 可以点击看看在线运行:http://hai…

    2025年12月24日 好文分享
    500
  • 10款好看且实用的文字动画特效,让你的页面更吸引人!

    图片和文字是网页不可缺少的组成部分,图片运用得当可以让网页变得生动,但普通的文字不行。那么就可以给文字添加一些样式,实现一下好看的文字效果,让页面变得更交互,更吸引人。下面创想鸟就来给大家分享10款文字动画特效,好看且实用,快来收藏吧! 1、网页玻璃文字动画特效 模板简介:使用css3制作网页渐变底…

    2025年12月24日 好文分享
    000
  • tp5如何引入css文件

    tp5引入css文件的方法:1、将css文件放在public目录下的static文件里即可;2、在页面引入中写上“”语句即可。 本教程操作环境:windows7系统、CSS3&&HTML5版、Dell G3电脑。 其实很简单,只需要将css,js,image文件放在这个目录下即可 页…

    2025年12月24日
    000
  • 聊聊CSS 与 JS 是如何阻塞 DOM 解析和渲染的

    本篇文章给大家介绍一下css和js阻塞 dom 解析和渲染的原理。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。 hello~各位亲爱的看官老爷们大家好。估计大家都听过,尽量将CSS放头部,JS放底部,这样可以提高页面的性能。然而,为什么呢?大家有考虑过么?很长一段时间,我都是知其…

    2025年12月24日
    200
  • js如何修改css样式

    js修改css样式的方法:1、使用【obj.className】来修改样式表的类名;2、使用【obj.style.cssTest】来修改嵌入式的css;3、使用【obj.className】来修改样式表的类名;4、使用更改外联的css。 本教程操作环境:windows7系统、css3版,DELL G…

    2025年12月24日
    000
  • 如何使用纯CSS、JS实现图片轮播效果

    本篇文章给大家详细介绍一下使用纯css、js实现图片轮播效果的方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。 .carousel {width: 648px;height: 400px;margin: 0 auto;text-align: center;position: a…

    2025年12月24日
    000
  • css怎么设置文件编码

    在css中,可以使用“@charset”规则来设置编码,语法格式“@charset “字符编码类型”;”。“@charset”规则可以指定样式表中使用的字符编码,它必须是样式表中的第一个元素,并且不能以任何字符开头。 本教程操作环境:windows7系统、CSS3&&…

    2025年12月24日
    000
  • js如何修改css

    js修改css的方法:1、使用【obj.style.cssTest】来修改嵌入式的css;2、使用【bj.className】来修改样式表的类名;3、使用更改外联的css文件,从而改变元素的css。 本教程操作环境:windows7系统、css3版,DELL G3电脑。 js修改css的方法: 方法…

    2025年12月24日
    000
  • js如何改变css样式

    js改变css样式的方法:1、使用cssText方法;2、使用【setProperty()】方法;3、使用css属性对应的style属性。 本教程操作环境:windows7系统、css3版,DELL G3电脑。 js改变css样式的方法: 第一种:用cssText div.style.cssText…

    2025年12月24日
    000

发表回复

登录后才能评论
关注微信