一个可能长期存在,但是不被注意,可能没有发生问题,但是存在隐患的问题

2020-09-17 11:10:29 +08:00
 Cbdy

最近看别人的代码,发现服务端的接口直接把数据库的实体传给了前端,这可能会导致一些隐患。

问题

比如某实体定义如下

data class LogEntity(
        val id: Long,
        val desc: String
)

val logEntity = LogEntity(id = 122337203685400001L, desc = "Some description")

转成 JSON 变成了

{
  "id":122337203685400001,
  "desc":"Some description"
}

然后前端把这个 JSON parse 成 JavaScript 对象,变成了

Object { id: 122337203685400000, desc: "Some description" }

LogEntity 的 ID 个位的 1 变成了 0,出现问题了。

这实际上是一个 JavaScript 的number类型处理数字的 feature,JavaScript 能准确表示-2^532^53之间的整数,具体可以看这个文章。然而有的语言的 Long 类型的范围是大于-2^532^53这个范围的,比如 Java 的Long的范围为-2^632^63-1,而在数据库里定义有符号的BIGINT,往往会用Long来在应用内存中表示。(当然实际实践中这么大的数字可能比较少见。)

所以比较合适的做法是在定义一个用于传输数据到前端的 DTO,把Long转成 JSON 支持的string类型,如

data class LogDTO(
        val id: String,
        val orderDesc: String
)

val logDTO = LogDTO(id = logEntity.id.toString(), desc = logEntity.desc)
// {"id":"122337203685400001","desc":"Some description"}

结论

在实践中使用专门定义的 DTO 传输数据确实是一个比较好的做法。除了上述的问题,其他的如 JSON 不支持时间,可以用 ISO8601 字符串或 UNIX 时间戳,JSON 不支持byte[],可以编码成 Base64 。

所以请不要直接向前端返回定义的用于 CURD 的数据库实体。

1462 次点击
所在节点    前端开发
2 条回复
sunjiayao
2020-09-17 11:16:09 +08:00
更大的问题是数据泄露。
kop1989
2020-09-17 11:18:00 +08:00
暴露给公网的 api 返回的一定得是针对 api 本身业务内容设计的 vo 也好,dto 也罢。
因为没必要暴露全部的 domain 字段。

至于说类型方面的序列化 /反序列化问题,谁做都行。
后端可以针对性转换,前端也可以。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/707841

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX