V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
qq7171891
V2EX  ›  Flask

Flask 框架如何直接获取 POST 请求的 JSON 原始数据?

  •  
  •   qq7171891 · 2016-02-22 13:09:21 +08:00 · 26756 次点击
    这是一个创建于 2985 天前的主题,其中的信息可能已经有所发展或是发生改变。
    自己做了个小网站接了第三方服务,第三方服务会 POST 一个 JSON 过来参与签名加密,我必须获取第三方 POST 过来的 JOSN 的原始数据才能正确效验。

    现在是用 Flask 的 request.get_json()去拿 JSON 数据,拿是可以拿到,但是拿到的数据已经不是原始数据了,被重新排序,键值对还加了空格,这样就不是原始的 JSON 了,加密效验也就无法完成。

    请求大神指点如何拿到原始的 JSON 数据。当然,要基于 Flask 的 route 。
    第 1 条附言  ·  2016-02-22 15:53:11 +08:00
    本帖问题已解决。
    第 2 条附言  ·  2016-02-23 17:39:32 +08:00
    解决方案: request.get_data()
    27 条回复    2016-02-23 11:47:11 +08:00
    windfarer
        1
    windfarer  
       2016-02-22 13:16:47 +08:00   ❤️ 1
    request.data
    qq7171891
        2
    qq7171891  
    OP
       2016-02-22 13:27:29 +08:00
    @windfarer 拿不到, request.data 仅在无法识别请求 mimetype 时才把数据放到这里面。第三方 POST 过来的数据类型明确是: Content-Type: application/json
    cxl008
        3
    cxl008  
       2016-02-22 13:34:42 +08:00
    如果第三方的程序员 直接用字典转成的 json ,那你这不是跪了,再怎么获取都没用啊。。。。
    billion
        4
    billion  
       2016-02-22 13:36:02 +08:00
    request.get_json()
    shidenggui
        5
    shidenggui  
       2016-02-22 13:37:05 +08:00 via Android   ❤️ 1
    看了下源码,用 get_json 是用的 requesr.get_data 获取的数据
    qq7171891
        6
    qq7171891  
    OP
       2016-02-22 13:37:23 +08:00
    @billion 兄弟。。题目中说了 request.get_json()会序列化 JSON 格式,序列出来的不是原始数据啊。
    qq7171891
        7
    qq7171891  
    OP
       2016-02-22 13:44:05 +08:00
    @cxl008 不是你理解的。

    需求是我方要效验对方接口的签名,以核实请求方的身份。
    请求方给我们一个公钥,自己用私钥把请求体的 JSON 进行加密运算,得出签名。对方请求我这边的时候会告诉我签名,以及 JSON ,我去拿对方给的公钥去计算,看看签名符合不符合。

    这就要求我从请求拿上来的 JSON 就是对方传给我的,现在的问题是我看了 FLASK 文档半天,只有 request.get_json()这个方法拿 JSON ,但是拿过来的已经是被格式化了的,不是原始数据了。
    jixiangqd
        8
    jixiangqd  
       2016-02-22 13:46:13 +08:00   ❤️ 1
    用 collections 里的 OrderedDict 反序列化 JSON....


    json.load(object_pairs_hook=collections.OrderedDict)
    jixiangqd
        9
    jixiangqd  
       2016-02-22 13:47:37 +08:00   ❤️ 1
    漏了个参数。。。 request.raw_data 没法编辑原回答,只能再回一次了

    json.load(request.raw_data,object_pairs_hook=collections.OrderedDict)
    shajiquan
        10
    shajiquan  
       2016-02-22 13:49:37 +08:00   ❤️ 1
    你可以拿到 request body ,但是这个 body 里的 JSON 字符串可能也是乱序的。而且这是无法避免的。

    既然如此的话,你就应该改变你的验证策略,比如说, JSON 数据中有一个字段专门就是 md5 之类的摘要,这个摘要是通过另外的值+私钥生成的,到你这边的时候,你根据私钥和 md5 摘要之外的其他数据来生成 md5 摘要,验证那个 md5 摘要是否和你的一致,这样是否 OK ?

    有必要时,再在 header 里加入一些标识,或者把 md5 摘要放在 header 里不要放在 json 里。

    前段时间我写了一个 API 供调用,用的就是这种思路,没有出现过问题。
    ethego
        11
    ethego  
       2016-02-22 13:50:14 +08:00
    json 对象不本来就是无序的吗?
    windfarer
        12
    windfarer  
       2016-02-22 13:51:05 +08:00   ❤️ 1
    @qq7171891
    我刚才试了一下,设置了 Content-Type: application/json 的 header 之后, request.data 里还是有数据的啊,难道是我姿势不正确。。
    baocaixiong
        13
    baocaixiong  
       2016-02-22 13:52:16 +08:00   ❤️ 1
    request.get_data()
    qq7171891
        14
    qq7171891  
    OP
       2016-02-22 14:08:13 +08:00
    @shajiquan 我也想。我直接说了,这是 pingxx 这个支付网关 Webhooks 回调签名方式,想他们改还是算了。
    qq7171891
        15
    qq7171891  
    OP
       2016-02-22 14:10:38 +08:00
    @windfarer 我再验证下。
    qq7171891
        16
    qq7171891  
    OP
       2016-02-22 14:30:28 +08:00
    @baocaixiong 这个一开始尝试过,转换的数据带了一个 b' 开头,再就是看文档说不推荐就没用了。那个 b' 可以弄掉?
    ethego
        17
    ethego  
       2016-02-22 14:34:03 +08:00   ❤️ 1
    @qq7171891 没有必要,这是个装饰符,代表字符串的类型是 bytes ,这个符号不会影响数据本身
    qq7171891
        18
    qq7171891  
    OP
       2016-02-22 15:15:28 +08:00
    @ethego 还是需要转换下字符串。


    @baocaixiong 谢谢你,怪我错误理解文档轻易放弃这个办法了,用 request.get_data()后转下码方案可行。

    另外谢谢:
    @windfarer
    @shajiquan
    @jixiangqd
    @windfarer

    以上 6 人,特别是 @baocaixiong ,我想给你们发支付宝红聊表心意,感谢你们对我这个初学者的帮助。

    但是 V2EX 貌似没私信啊~~能否告诉我你们的支付宝账号?
    qq7171891
        19
    qq7171891  
    OP
       2016-02-22 15:17:46 +08:00
    哦。。忘记说了。
    @baocaixiong 30 ,其余每人 20 。钱不多,聊表心意。支付宝是邮箱账号的话公布出来应该没啥问题吧。。
    真希望 V2EX 开个打赏功能。。。
    windfarer
        20
    windfarer  
       2016-02-22 15:22:55 +08:00 via iPhone   ❤️ 1
    问题解决了就好,何必客气嘛
    mulog
        21
    mulog  
       2016-02-22 15:24:51 +08:00   ❤️ 1
    楼主好人啊 赞
    不过呢建议你还是善用搜索 google 'flask get raw request data' 出来第一条就有答案告诉你 request.get_data()
    qq7171891
        22
    qq7171891  
    OP
       2016-02-22 15:36:59 +08:00
    @windfarer 谢谢。

    以上楼层有用答案的我都送铜币了,一层送一份,不管是不是同一个人。

    后续我看到本帖之前说的几位前辈有留支付宝账号的,我会立刻发红包。

    再次感谢各位。
    baocaixiong
        23
    baocaixiong  
       2016-02-22 15:39:16 +08:00   ❤️ 1
    @qq7171891 不客气,楼主好好学习
    lixiaohan
        24
    lixiaohan  
       2016-02-22 15:47:31 +08:00
    request.get_data() 看源码 或者官方文档就有
    http://www.pythondoc.com/flask/api.html
    shajiquan
        25
    shajiquan  
       2016-02-22 16:01:35 +08:00
    @qq7171891 不客气。互相交流。
    jixiangqd
        26
    jixiangqd  
       2016-02-22 16:15:05 +08:00
    楼主真是太客气了,铜币已收到, rmb 就算了~v2 就是用来交流技术的嘛,你给钱不坏了风气。。。顺手回一下而已。
    现在用 django 比较多,可能记混了,忘了 flask 的 raw_data 的取值方式,可能有些误导了,抱歉,哈哈哈。。
    WhyLiam
        27
    WhyLiam  
       2016-02-23 11:47:11 +08:00
    为什么我不记得 ping++ Webhooks 要这么复杂
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3565 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 10:45 · PVG 18:45 · LAX 03:45 · JFK 06:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.