Python “安全”序列化复杂对象的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
gosky
V2EX    Python

Python “安全”序列化复杂对象的问题

  •  
  •   gosky 2024-08-14 17:07:03 +08:00 1668 次点击
    这是一个创建于 447 天前的主题,其中的信息可能已经有所发展或是发生改变。
    需求是:
    接口里,有多处渲染图片的逻辑
    想把渲染图片的逻辑放到一个个单独的渲染接口

    原接口返回的响应,原本带了几个图片的 base64 ,现在改为带几个图片的渲染参数
    前端拿到渲染参数,拼成一个图片 url ,再请求 当然,这里必须是 get ,渲染参数也不能嵌套
    渲染接口,接到渲染参数,再渲染图片,返回一个图片响应到前端

    渲染参数结构大致是这样的:
    {
    code: "123",
    type: "xyz",
    param: "..."
    }

    这个渲染参数,是一个两层结构
    具体的渲染参数都在 param 中,code 和 type 只是用来找到具体的渲染口子
    因为渲染接口只能是 get ,param 给前端必须是字符串
    后端拿到渲染参数第一步,解析出 code 和 type ,找到渲染口子。渲染口子内部再解析 param
    之前没多想,把渲染参数 json 序列化,赋值给 param
    没想到 json 序列化渲染参数时,会将 param 的 json 进行转义…… 导致反序列化时,param 反序列化报错

    当然,有几个可行的方案:
    一、ensure_ascii=False 不转义。这会影响全局。因为渲染参数响应,它的序列化是全局逻辑
    二、忽略渲染参数的两层结构,直接完整的序列化和反序列化
    三、param 先 json 序列化,再 base64 安全编码。这个问题是多了一部操作,且输出结果人类不可读
    四,反序列化 param 时,先反转义

    求一个更加优雅的方案

    我需要的,也许是一个“安全”的序列化方法, 能将 param 数据,序列化为不需要转义的数据。但 python 没有 safe 的 json 方法。base64 倒是一般都有
    js 有一个库,https://www.npmjs.com/package/qs ,可以将 js 嵌套对象、数组对象编码为查询字符串
    但 python 好像没这样的库
    第 1 条附言    2024-08-14 17:39:18 +08:00
    分析和描叙都不到位

    目的是要把嵌套的 param ,安全编码,作为查询参数
    第 2 条附言    2024-08-19 09:40:26 +08:00
    结果:
    一般客户端应用程序、客户端库都自动会将查询参数值转义。但当时我用的客户端是 postman ,postman 并没有对参数值转义,导致出现意外情况。部分客户端应用程序的转义逻辑有点奇怪,但眼下只有一个客户端程序,所以不用考虑到这点。

    最终方案:服务端业务逻辑将 param 对象 json 序列化/反序列化就好。其它交给各处自动处理。
    9 条回复    2024-08-14 18:49:45 +08:00
    tianzhongs
        1
    tianzhongs  
       2024-08-14 17:21:56 +08:00
    可以使用自定义的编码方式来处理这个问题。思路如下:
    对于 param 中的数据,将其键值对按照一定规则拼接成字符串,而不是直接使用 JSON 序列化。
    例如,如果 param 是 {"key1": "value1", "key2": "value2"},可以将其拼接为 key1=value1&key2=value2 的形式。
    在前端和后端约定好这个编码规则。
    前端在发送请求时,按照这个规则将 param 中的数据拼接成字符串,然后将整个渲染参数对象构建成 URL 的查询参数形式。
    后端接收到请求后,先解析出 code 和 type ,然后根据约定的规则将 param 部分的字符串再解析回键值对的形式。
    这样做的好处有:
    不需要依赖复杂的第三方库或者特殊的设置(如 ensure_ascii=False ),并且完全符合只能使用 GET 请求且参数不能嵌套的要求。
    避免了 JSON 序列化可能带来的转义问题,同时也没有增加过多的复杂操作(相比于先序列化再 base64 编码的方式)。
    输出的结果相对简洁且人类可读程度较高,只要了解规则,在调试等情况下也比较容易理解。
    sagaxu
        2
    sagaxu  
       2024-08-14 17:25:22 +08:00
    JSON 编码解码,是 JSON 规范,不会因为转义不转义失败。
    URL 的 Query String ,也有自己的编码规范。

    两件事情是完全不相干的,要分别处理,难不成你指望 JSON 序列化后的东西直接拼 URL 里用?
    tolbkni
        3
    tolbkni  
       2024-08-14 17:30:57 +08:00
    ```python
    from urllib.parse import parse_qs
    y = parse_qs('a=c')
    ```
    gosky
        4
    gosky  
    OP
       2024-08-14 17:37:42 +08:00
    @tianzhongs param 内部是嵌套的哦
    gosky
        5
    gosky  
    OP
       2024-08-14 17:38:36 +08:00
    @sagaxu 前面分析不到位
    准确地说,就是要把 param 安全编码,作为查询参数
    sagaxu
        6
    sagaxu  
       2024-08-14 17:43:35 +08:00
    @gosky 常规做法是先 JSON 序列化变 str ,再 URL 转义拼参数中,后端拿到 str 后直接 JSON 解码得到原始参数
    MoYi123
        7
    MoYi123  
       2024-08-14 17:46:51 +08:00   1
    问题最关键的 param 是怎么样子的, 让你用 param: "..." 这样三个点跳过了.
    gosky
        8
    gosky  
    OP
       2024-08-14 18:15:25 +08:00
    @MoYi123 不固定哦 可能有嵌套结构和列表
    MoYi123
        9
    MoYi123  
       2024-08-14 18:49:45 +08:00
    @gosky 所以需要你给一些例子啊.
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2901 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 14:26 PVG 22:26 LAX 06:26 JFK 09:26
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86