设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间07 现在时间07 缓存数据 女人不要只算计自己喜欢的任何物品多少钱,要计算自己的青春还剩多少年;要懂得爱自己,舍得爱自己;不为别人,只为那个限量版的自己!

女人不要只算计自己喜欢的任何物品多少钱,要计算自己的青春还剩多少年;要懂得爱自己,舍得爱自己;不为别人,只为那个限量版的自己!

查看: 835|回复: 0

Laravel 自动转换长整型雪花 ID 为字符串的实现

[复制链接]

  离线 

TA的专栏

  • 打卡等级:即来则安
  • 打卡总天数:23
  • 打卡月天数:0
  • 打卡总奖励:345
  • 最近打卡:2025-04-09 00:30:25
等级头衔

等級:晓枫资讯-上等兵

在线时间
0 小时

积分成就
威望
0
贡献
419
主题
393
精华
0
金钱
1588
积分
860
注册时间
2023-2-10
最后登录
2025-4-9

发表于 2023-2-12 20:43:04 | 显示全部楼层 |阅读模式
在设计 API 时,出于安全性等因素考虑,有时需要放弃使用自增 ID,使 ID 非连续且不可猜测。通常可以使用 Hash id,UUID,雪花 ID 等来实现。
在最近的一个项目中,我尝试使用雪花 ID。一通折腾下来发现,逼格挺高,实现也挺简单。然而当我继续撸起袖子与前端部分对接时,却出现了 JS 精度丢失问题,因为存储的 ID 是一个 unsigned bigint 型的值。(至于为什么会有精度丢失现象,这里就不具体解释了,不清楚的可以自行搜索),本文主要介绍解决办法。
想要解决这问题,基本原理也很简单,就是把 ID 转成字符串再返回给前端。
错误尝试

一开始我想到的是使用 Laravel Eloquent 模型的模型访问器。只要给需要转换的模型加一个 getIdAttribute,将 ID 转成字符串不就行了嘛?
如:AppModelsUser 模型里这样写:
  1. /**
  2. * @return string
  3. */
  4. public function getIdAttribute()
  5. {
  6.   return strval($this->attributes['id']);
  7. }
复制代码
但事实并非如此,属性访问器确实能让 API 返回给前端的 ID 变为字符串。但同时也会影响关联模型插入、修改时的结果,例如,user 关联的了 post 模型,使用 $user->posts()->saveMany(...); 这种方式保存的新的 posts 记录,对应的 user_id 会为空。
这也不难理解,因为模型访问器是要参与模型相关处理的,访问器将 ID 由数字转为了字符串,自然会导致数据错乱。
正确姿势

冷静下来决定先认真思考再动手,查阅了官方文档,才发现 Resource 正是我想要的。Resource 只会影响返回给前端的数据,我们可以通过自定义 Resource 来实现 API 返回结果的结构、类型转换等功能。转换个 ID 自然也不在话下。
为了省事,我直接修改 AppHttpResource 这个基类。只需要重载它的 toArray() 方法,在其中使用递归,对可能超出 JS 安全数值范围的值进行转换就可以了。大家也可以根据自己的实际情况,新建 Resource 类,如 UserResource 来处理。
  1. <?php

  2. namespace App\Http\Resources;

  3. use Illuminate\Http\Resources\Json\JsonResource;

  4. class Resource extends JsonResource
  5. {
  6.   /**
  7.    * Transform the resource into an array.
  8.    *
  9.    * @param \Illuminate\Http\Request $request
  10.    *
  11.    * @return array
  12.    */
  13.   public function toArray($request)
  14.   {
  15.     $parentReturn = parent::toArray($request);

  16.     foreach (array_keys($parentReturn) as $key) {
  17.       // 为方便演示这里把所有整型字段都转成字符串
  18.       if (is_int($parentReturn[$key])) {
  19.         $parentReturn[$key] = strval($parentReturn[$key]);
  20.       }

  21.       // 关联的字段,如 $user->post,相当于递归处理
  22.       if (is_array($parentReturn[$key])) {
  23.         $parentReturn[$key] = new Resource($parentReturn[$key]);
  24.       }
  25.     }

  26.     return $parentReturn;
  27.   }
  28. }
复制代码
然后,在接口控制器中返回 Resource 返回数据,整型字段值就会自动变为字符串了。
  1. <?php

  2. namespace App\Http\Controllers;

  3. use App\Http\Resources\Resource;
  4. use App\Models\User;
  5. use Illuminate\Http\Request;

  6. class TestController extends Controller
  7. {
  8.   /**
  9.    * @return \App\Http\Resources\Resource
  10.    */
  11.   public function __invoke(Request $request)
  12.   {
  13.     $user = User::first();

  14.     return new Resource($user);
  15.   }
  16. }
复制代码
结果如下图:
214333si4qu2okbuk5rqbe.jpg

注意事项

因为这种办法使用了遍历,而且有递归处理,当数据结构复杂、数据量较大时可能会对性能造成一定影响。我这里算是比较偷懒取巧的写法,如果对性能有追求,自定义 Resource 类,然后根据特定的已知的字段名来进行转换会比较好
因为返回给前端的 ID 转为了字符串,前端在进行比较判断,特别是 === 判断时要特别注意

到此这篇关于Laravel 自动转换长整型雪花 ID 为字符串的实现的文章就介绍到这了,更多相关Laravel 长整型雪花ID转换为字符串内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表