Laravel API更换主机后JSON返回值数据类型不一致问题解决
解决Laravel API迁移后JSON整数类型差异的问题
这个问题我之前也碰到过,核心原因是PHP/Laravel版本升级后,Eloquent对数据库字段类型的序列化逻辑发生了变化——旧环境下(PHP7.0+旧版Laravel)会把整数类型的数据库字段转成字符串返回,而新环境(PHP7.1+新版Laravel)则会保留原生的整数类型,导致返回的JSON格式出现差异。下面给你几个实用的修复方案:
方案1:使用Laravel模型的$casts属性(推荐)
这是最符合Laravel最佳实践的方式,通过在模型中明确指定字段的输出类型,强制把整数字段转成字符串。
比如在你的Items模型中添加以下代码:
protected $casts = [ 'category_id' => 'string', 'price' => 'string', 'is_special_offer' => 'string', 'status' => 'string', // 如果还有其他需要转字符串的整数字段,也可以在这里添加 ];
如果Categories模型中的status字段也需要保持字符串格式,同样在Categories模型中添加对应的$casts配置:
protected $casts = [ 'status' => 'string', ];
这样Eloquent在序列化模型数据时,会自动把指定字段转换成字符串类型,不管数据库字段本身是什么类型,返回的JSON格式就能和旧环境保持一致了。
方案2:手动遍历集合转换字段类型
如果不想修改模型,或者只是临时修复特定接口,可以在返回JSON前手动遍历集合,把需要的字段转成字符串:
public function getAllCategories(){ $info = Categories::with([ 'items' => function($q){ $q->with(['item_services' => function($qq){ $qq->with( ['service' => function($qqq){ $qqq->select( 'id', 'name', 'image', 'status' ); }]); }])->select( 'id', 'category_id', 'name', 'image', 'price', 'new_price', 'discount', 'discount_description', 'is_special_offer', 'has_merzam', 'has_taneem', 'neela', 'nasha', 'status'); }])->select('id', 'name', 'image', 'status')->get(); // 手动转换整数字段为字符串 $info = $info->map(function($category) { // 转换Category模型的status字段 $category->status = (string)$category->status; // 转换Items模型的相关字段 $category->items = $category->items->map(function($item) { $item->category_id = (string)$item->category_id; $item->price = (string)$item->price; $item->is_special_offer = (string)$item->is_special_offer; $item->status = (string)$item->status; // 如果item_services里的service也需要转换status,继续嵌套处理 $item->item_services = $item->item_services->map(function($service) { $service->service->status = (string)$service->service->status; return $service; }); return $item; }); return $category; }); return response()->json(['status' => true, 'message' => trans('messages.success_message'), 'errors' => [], 'data' => $info]); }
这种方式比较灵活,但如果字段较多或者关联层级复杂,代码会显得繁琐。
方案3:全局修改JSON序列化行为(谨慎使用)
如果你的所有API接口都需要把整数转成字符串,可以通过自定义响应宏来实现全局转换。在app/Providers/AppServiceProvider.php的boot方法中添加以下代码:
use Illuminate\Support\Facades\Response; public function boot() { // 定义一个自定义的JSON响应宏,自动把所有整数转成字符串 Response::macro('jsonWithStringInts', function ($data) { $transformed = $this->transformIntsToString($data); return response()->json($transformed); }); } // 递归遍历数据,把所有整数转成字符串 private function transformIntsToString($data) { if (is_array($data) || $data instanceof \Illuminate\Support\Collection) { foreach ($data as $key => $value) { $data[$key] = $this->transformIntsToString($value); } return $data; } if (is_int($data)) { return (string)$data; } return $data; }
然后在接口中使用这个自定义响应宏返回数据:
return response()->jsonWithStringInts(['status' => true, 'message' => trans('messages.success_message'), 'errors' => [], 'data' => $info]);
注意:这个方案会影响所有使用该宏的接口,如果你有部分接口需要保留整数类型,就不太适用了。
内容的提问来源于stack exchange,提问作者Mohammed H. Alghazali
相关产品推荐
相关产品推荐

