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

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

  •  
  •   cielpy · 8 天前 · 2539 次点击

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

    {
        type: 0
    }
    

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

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

    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   8 天前 via Android
    可以强制后端所有的值全部字符串啊
        2
    cielpy   8 天前
    @assad 强转字符串不太优雅吧,有些是 number 类型的客户端处理起来就自然多了,不用转,直接拿来数值就判断了
        3
    mht   8 天前 via iPhone
    存在这个情况,习惯好点的肯定会给你转成 int 型
        4
    cielpy   8 天前
    @mht 每个字段读出来后手动转,这样吗
        5
    mahone3297   8 天前
    我觉得不存在。。。int 就是 int。除非,太长的 integer,会自动转成 string 好像
        6
    est   8 天前
    我还以为你想说 type 是关键字。


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

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

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

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



    -- 分割线 --


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

    沟通下不就 ok 了么!

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

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

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

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

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