
最近看别人的代码,发现服务端的接口直接把数据库的实体传给了前端,这可能会导致一些隐患。
比如某实体定义如下
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^53到2^53之间的整数,具体可以看这个文章。然而有的语言的 Long 类型的范围是大于-2^53到2^53这个范围的,比如 Java 的Long的范围为-2^63到2^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 的数据库实体。
1 luman 2020-09-17 11:16:09 +08:00 更大的问题是数据泄露。 |
2 kop1989 2020-09-17 11:18:00 +08:00 暴露给公网的 api 返回的一定得是针对 api 本身业务内容设计的 vo 也好,dto 也罢。 因为没必要暴露全部的 domain 字段。 至于说类型方面的序列化 /反序列化问题,谁做都行。 后端可以针对性转换,前端也可以。 |