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

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

  •  
  •   cielpy · 2018-01-09 22:49:46 +08:00 · 9868 次点击
    这是一个创建于 2270 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    {
        type: 0
    }
    

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

    第 1 条附言  ·  2018-01-11 10:31:07 +08:00
    感谢各位的回复

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


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

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

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

    其实很简单,php 端加个类型转换的事,当然他可能让你们自己转换,那看你们协商的情况了
    crysislinux
        35
    crysislinux  
       2018-01-10 10:39:26 +08:00
    赞同 LS 的,这不是 PHP 的问题,这是你们后端实现的 bug
    tailf
        36
    tailf  
       2018-01-10 10:51:56 +08:00   ❤️ 2
    楼上没有一个有正确姿势的。



    -- 分割线 --


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

    沟通下不就 ok 了么!

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

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

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

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

    至少数据库的查询结果,会保持默认的数据类型,不会把 int 类型转为 string。
    AidenChen
        73
    AidenChen  
       2018-01-11 15:54:03 +08:00
    使用 mysqlnd 驱动,这样从 Mysql 取出来的数字就不会变成字符串了
    cielpy
        74
    cielpy  
    OP
       2018-01-11 17:20:38 +08:00
    @nekoyaki 看了这个博客 http://www.druidcoder.cn/2016/05/10/mysql-driver/ php 的数据库驱动在 5.3 之前读出来是都是字符串的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1002 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 73ms · UTC 20:03 · PVG 04:03 · LAX 13:03 · JFK 16:03
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.