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

PHP 接口返回 JSON 数据保证正确的类型难(或者麻烦)在哪?

  •  
  •   cielpy · 339 天前 · 5571 次点击
    这是一个创建于 339 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一直以来有一个疑问,和后端同事合作时定好了接口文档,如:

    {
        type: 0
    }
    

    定义好 type 是 number 类型,返回数据一会儿是 string,一会儿是 number 类型,问他们说代码都没改,返回数据的类型变了,Google 一下似乎是有这个问题,但是没有找到一个好的解决方案,我不是写 PHP 的,可能找解决方案的姿势不对,所以想请问一下各位 PHPer,这个问题真的存在吗?如果存在,解决起来有多麻烦?正确的解决方式是什么呢?

    第 1 条附言  ·  337 天前
    感谢各位的回复

    0x00
    没有引战的意思,纯粹是因为这个问题之前和同事没有讨论出来一个好的处理结果来 v2 问一下

    0x01
    感谢 @klgd 的指点,昨天问了一下,我们是用 Yii2 这个框架的,不是在读 MySQL 时出的问题,是在框架层的处理导致都成了字符串

    0x02
    关于解决方案,目前看来有几个

    1. 强转,封装数据的时候先强转成指定的类型 (int)type_var,这个对客户端友好一点,对后端来说比较繁琐
    2. 全部转成字符串,这个对后端友好,客户端处理起来就不太好,有些类型对应一个枚举,解析后客户端处理起来很方便
    3. 客户端的兼容办法我想在后端实在处理不好的时候再上,而且目前没有想到太好的办法处理这个兼容
    4. 换数据交换方式 Protobuf 或者 GRPC,这个目前不会考虑,改动太大了
    5. JSON_NUMERIC_CHECK 参数
    6. 做一个统一的格式化返回函数, code msg data. 但是 data 还是一个对象,这个对象的内容还是不定的,再加一个格式化函数?
    7. http://json-schema.org 要做一些额外的类型限制工作

    0x03
    「问他们说代码都没改,返回数据的类型变了」这个肯定是后端处理的问题,这个还是可以沟通的
    74 回复  |  直到 2018-01-11 17:20:38 +08:00
        1
    assad   339 天前 via Android
    可以强制后端所有的值全部字符串啊
        2
    cielpy   339 天前
    @assad 强转字符串不太优雅吧,有些是 number 类型的客户端处理起来就自然多了,不用转,直接拿来数值就判断了
        3
    mht   339 天前 via iPhone
    存在这个情况,习惯好点的肯定会给你转成 int 型
        4
    cielpy   339 天前
    @mht 每个字段读出来后手动转,这样吗
        5
    mahone3297   339 天前
    我觉得不存在。。。int 就是 int。除非,太长的 integer,会自动转成 string 好像
        6
    est   339 天前
    我还以为你想说 type 是关键字。


    返回一个 {for: 0} 估计会在某些情况下让人哭。
        7
    cielpy   339 天前
    @est 不是啦,type 是一个字段名😂
        8
    cxbig   339 天前
    作为数据提供方,我会考虑在输出 JSON 以前,加强制类型转换。特别是文档已经明确标注类型的情况下。
    作为数据接受方,我也会先做数据整形,再处理。
        9
    IceBay   339 天前   ♥ 1
    大概是
    ```
    return response(['status_code' => 201]);
    ```

    ```
    return response(['status_code' => '201']);
    ```
        10
    dangyuluo   339 天前
    麻烦在前端看不起 PHP,与后端缺乏沟通方法,沟通效率低上。
        11
    Immortal   339 天前
    我听一个朋友说 他在返回数据那统一全部转成了 string
    一般我这边客户端(app)也会做数据格式兼容,防止服务端(我)有时候没注意数据格式直接崩了
        12
    alinwu05   338 天前 via Android
    肯定是改代码啦,不是语言的锅
        13
    lzvezr   338 天前 via iPhone
    反正我利用过 api 返回类型不同获取用户隐私数据,所以以防万一还是后端检查一下代码统一数据类型比较好
        14
    he583899772   338 天前
    数据传输不都是字符串的形式传递嘛
        15
    raysonlu   338 天前
    统一用字符串呗,或者接收端自己做检查,查数据库得到的都是字符串啊,你要 php 一个一个给你转类型?逃)
        16
    azh7138m   338 天前 via Android
        17
    pubby   338 天前 via Android
    不难,偷懒而已
        18
    alexzhou   338 天前
    接口这种东西 预定好了的 就要返回照着约定返回 管你后端用什么语言。 问题不难解决 就看做不做了
        19
    lepig   338 天前
    数据库默认查出来的就算是 int 也会返回 string
    对于 php 这种弱类型语言 前端在判断时最好自己也转一下。就像提交表单的时候后端也不会相信前端输入,肯定会在做一次检测
        20
    Moker   338 天前
    return 的时候直接加( int )一般这样做 只是看想不想
        22
    LeungJZ   338 天前
    因为从数据库里面查出来的吧?即使是 int,到 php 也会成了 String。
    最简单的方法是,让后台在所有要转成 int 型的变量前面加个 + 即可。
        23
    not4jerk   338 天前
    ```php
    json_encode($arrayOrObject, JSON_NUMERIC_CHECK)
    ```
    在叫你们 PHP 后端在加上这个参数`JSON_NUMERIC_CHECK` 使用的字符数字都会变成`json-number`

    垃圾 thinkPHP3 默认返回 json 就是数字字符分不清
        24
    qqjt   338 天前
    这肯定是后端要做的工作啊,不按定义好的来算 bug 啊
        25
    lrh3321   338 天前
    类型不对,直接返回错误,我就当被攻击了。文档都定义好了,不按文档来,就别怪后端不返回数据了。
        26
    nullen   338 天前
    让服务端 PHP 做一下类型转换:
    [
    'type': (int) $type
    ]
        27
    owenliang   338 天前
    客户端自己处理。
        28
    alex321   338 天前
    尤其 MySQL 中是 int,查询直接返回会存在变成 string 的情况,得强制 int 一下。。。。
        29
    enenaaa   338 天前
    @not4jerk 这样会把纯数字的字符串当成数字类型。
    php 这个问题有点蛋疼。
        30
    8355   338 天前
    基础格式化问题啊.
    做一个统一的格式化返回函数, code msg data.
    code 和 msg 强制转字符串 data 强制数组
    做这个的意义不仅仅是数据类型层面的还能避免手误 比如 code 打成 cdoe
        31
    jea   338 天前
    这东西, 前后端商量好一个类型, 自然就是后端处理固定类型了
        32
    daryl   338 天前
    php 在 json_encode 数组元素强制类型转换成需要的类型就好了。这不是实现不了,就是懒= =
        33
    Raidal   338 天前
    强制转换也挺蛋疼的
        34
    yujieyu7   338 天前
    后端 php 的锅没跑,“问他们说代码都没改,返回数据的类型变了”,那这是 bug 让他给修啊

    其实很简单,php 端加个类型转换的事,当然他可能让你们自己转换,那看你们协商的情况了
        35
    crysislinux   338 天前
    赞同 LS 的,这不是 PHP 的问题,这是你们后端实现的 bug
        36
    tailf   338 天前   ♥ 2
    楼上没有一个有正确姿势的。



    -- 分割线 --


    http://json-schema.org 我已经成功用上。
        37
    lshero   338 天前
    还好你没有遇到一会儿空对象一会儿空数组的问题
        38
    iyaozhen   338 天前 via Android
    「定义好 type 是 number 类型,返回数据一会儿是 string,一会儿是 number 类型,问他们说代码都没改,返回数据的类型变了」
    就是 bug 呀,改不了找上级,还改不了楼主想想年后是不是换个公司
        39
    omph   338 天前
    @tailf 用这个做接口约定,可读性、性能都怎么样?
        40
    jason19659   338 天前
    提 bug。。
    还有
    {
    "type": 0
    }
        41
    cielpy   338 天前
    @lshero 遇到了。。没写进来
        42
    jswh   338 天前
    一切都按文档来,文档没写的约定好了,写进文档,让后再按文档来,省的扯皮,然后该怎么写怎么写,该强制类型转换就转换。
    代码都没改,返回数据的类型变了,这种基本上是底下的代码变了。
        43
    tailf   338 天前
    @omph JSON 描述的格式,不会经常改的,实测好用。
        44
    lshero   338 天前
    @cielpy 其实后端可以输出前先构造好要输出的结构体,再去填充数据,并在输出前进行校验。但是影响 QPS 和增加工作量的事肯定不改,这事情只能找上级推动了。比如如果你们是移动端的话,你们可以把最近因为后端输出数据不标准导致的奔溃已经影响的范围的数据摆出来,让上级来推动这件事情。
        45
    sagaxu   338 天前
    动态一时爽
        46
    cccRaim   338 天前
    明显是后端甩锅
        47
    free9fw   338 天前
    完全是看 PHP 开发人员的水平的,更有甚者,返回的 json 是这样的:{"1": "a", "2": "b", ...}
        48
    Felldeadbird   338 天前
    后端没有明确返回类型。这一点 PHP 对接其他语言特别容易遇到。
        49
    DamonLee   338 天前
    一线城市回到三线老家找到的公司就这样,两个 php,都不按套路出牌,有一次改个版本更新接口,她改来改去就是一直是 string,最后我妥协了,还是安卓和 iOS 来改吧,耽误不起那个时间啊
    PS:php 是技术部负责人
        50
    tagtag   338 天前
    在变量前面用
    (int)$type;或者(string)$type;强制转换下应该就行了。
        51
    glues   338 天前
    PHP 果然是最好的语言
        52
    hand515   338 天前
    换强类型语言
        53
    ylsc633   338 天前
    这又是故意拉战的!

    沟通下不就 ok 了么!

    这跟昨天那个 前端校验和后端校验的问题一模一样!

    要是牛 x,可以自己前后端一起搞啊!真的是...

    不沟通..肯定是这个问题!
        54
    yxn1910   338 天前
    可以试试 GRPC 或者直接用 Protobuffer 来交换数据
        55
    AllBlueAwei   338 天前
    一般直接从数据库查询出来的数据是不会出现这种情况的吧,看了你的问题,我也马上回去看看我的接口文档是否也出现过这样的问题,结果是没有的,应该是后台程序员处理某一段逻辑的时候使数据类型发生改变了,而且我个人也不建议强制转换数据类型,这个肯定不是语言的锅,八成是程序写的有问题
        56
    ZXCDFGTYU   338 天前
    api 接口文档里强制定义数据类型,后端看了会明白的。如果不明白那他也不要做后端了。
        57
    jea   338 天前
    @glues 虽然 PHP 是弱类型语言, 但主要还是看写东西的人, 这个还是能定义的
        58
    njwangchuan   338 天前
    这锅怎么也轮不到 php 背吧。后端水平 low,用什么语言写出来的东西都只能是一坨屎。这种情况直接让他搜索 ecma404
        59
    fcten   338 天前
    要保证数据类型一点都不麻烦……返回之前强制转换一下就好了
        60
    saintatgod   338 天前
    #代码都没改,返回数据的类型变了# 这是人为的,
        61
    walkonthemarz   338 天前 via Android
    没装 mysqlnd 吧
        62
    wslsq   338 天前
    建议强转 string 吧,js 无法处理小数和太长的整数
        63
    ixiaohei   338 天前
    java 语言从不纠结这个问题....,你这边定义啥类型就 json 反序列化就帮你转啥类型
        64
    Heartbleed   338 天前 via Android
    The Key
        65
    torbrowserbridge   338 天前 via Android
    和数据库驱动有关系,和客户端查询选项有关系。
        66
    lihongjie0209   338 天前
    动态一时爽
        67
    python   338 天前
    动态一时爽
        68
    billlee   338 天前
    在于 php 是动态类型 + 弱类型,一不小心就搞错了,Java 就很少搞错。
        69
    cielpy   337 天前
    @8355 每个接口的 data 数据不一样呢
        70
    gouchaoer   337 天前
    一般从数据库取出来的或者从 POST/GET/SESSION 读入的都是 string,有的参数如果是人工赋值的就是 int,这个显然是 php 后台没有做好
        71
    nekoyaki   337 天前
    我看了一下这帖子的评论,我不懂 php,按我的理解,似乎 php (或者可能你们其实是指某 php 的常用框架 /数据库驱动?),从数据库里读出来的字段都强行默认成 string,需要手工处理,是这样吗?

    评论里其他人有不少把原因归结为是动态类型 /弱类型的问题,这个肯定是不对的。典型的动态类型语言,比如 python/ruby,从来没有哪个数据库里的数值型字段,读出来竟然默认会变成 string,竟然还需要手工强转的。
        72
    ipom   337 天前
    设置一下 PDO 的属性:
    Pdo::ATTR_EMULATE_PREPARES => false,
    Pdo::ATTR_STRINGIFY_FETCHES => false

    至少数据库的查询结果,会保持默认的数据类型,不会把 int 类型转为 string。
        73
    AidenChen   337 天前
    使用 mysqlnd 驱动,这样从 Mysql 取出来的数字就不会变成字符串了
        74
    cielpy   337 天前
    @nekoyaki 看了这个博客 http://www.druidcoder.cn/2016/05/10/mysql-driver/ php 的数据库驱动在 5.3 之前读出来是都是字符串的
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   752 人在线   最高记录 4019   ·  
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.1 · 20ms · UTC 21:08 · PVG 05:08 · LAX 13:08 · JFK 16:08
    ♥ Do have faith in what you're doing.
    沪ICP备16043287号-1