Laravel API空对象被转为空数组的问题及解决方案尝试
Laravel API中空对象被转为空数组的解决方案
问题背景
向Laravel API发送包含空对象的JSON请求时,空对象会被自动转换为空数组,无法原样存入数据库。
请求体示例:
{ "shouldBeEmptyArray": [], "shouldBeEmptyObject": {} }
控制器直接返回请求内容时,响应结果:
[ [], [] ]
问题根源
Laravel的Illuminate\Http\Request类中,json()方法调用json_decode($this->getContent(), true)时,将associative参数设为true,会把所有JSON对象转为关联数组,空对象{}因此被转为空数组[]。框架源码如下:
/** * Get the JSON payload for the request. * * @param string|null $key * @param mixed $default * @return \Symfony\Component\HttpFoundation\ParameterBag|mixed */ public function json($key = null, $default = null) { if (! isset($this->json)) { $this->json = new InputBag((array) json_decode($this->getContent(), true)); } if (is_null($key)) { return $this->json; } return data_get($this->json->all(), $key, $default); }
提问者曾尝试自定义Request类重写json()方法,但未成功,自定义代码如下:
<?php namespace App\Http\Requests; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\InputBag; class RequestJsonOverride extends Request { /** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize() { return true; } /** * Get the validation rules that apply to the request. * * @return array<string, mixed> */ public function rules() { return [ // ]; } public function json($key = null, $default = null) { if (! isset($this->json)) { $this->json = new InputBag((array) json_decode($this->getContent(), false)); } if (is_null($key)) { return $this->json; } return data_get($this->json->all(), $key, $default); } }
有效解决方案
方案1:直接获取原始JSON并解析
在控制器或自定义请求类中,跳过Laravel默认的参数解析,直接获取原始请求内容并按需求解析:
// 控制器中获取原始解析结果 $rawPayload = json_decode($request->getContent(), false); // 此时$rawPayload->shouldBeEmptyObject是stdClass空对象,可直接存入JSON类型的数据库字段 YourModel::create([ 'shouldBeEmptyArray' => $rawPayload->shouldBeEmptyArray, 'shouldBeEmptyObject' => $rawPayload->shouldBeEmptyObject ]);
方案2:给Request添加自定义宏(全局可用)
在App\Providers\AppServiceProvider的boot()方法中添加自定义宏,用于获取保留原始类型的JSON数据:
use Illuminate\Http\Request; public function boot() { Request::macro('rawJson', function ($key = null, $default = null) { $decoded = json_decode($this->getContent(), false); return is_null($key) ? $decoded : data_get($decoded, $key, $default); }); }
之后在任意控制器中可直接使用:
$emptyObject = $request->rawJson('shouldBeEmptyObject'); // 得到stdClass空对象
方案3:修正自定义Request类的重写逻辑
原重写代码的问题在于将stdClass对象强制转为数组存入InputBag,导致空对象再次变为空数组。修改为递归保留空对象的结构:
<?php namespace App\Http\Requests; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\InputBag; class RequestJsonOverride extends Request { public function authorize() { return true; } public function rules() { return []; } public function json($key = null, $default = null) { if (! isset($this->json)) { $decoded = json_decode($this->getContent(), false); $this->json = new InputBag($this->preserveEmptyObjects($decoded)); } return is_null($key) ? $this->json : data_get($this->json->all(), $key, $default); } private function preserveEmptyObjects($data) { if (is_object($data)) { $arrayData = (array)$data; // 空对象转为(object)[]保留类型 return empty($arrayData) ? (object)[] : $this->preserveEmptyObjects($arrayData); } if (is_array($data)) { foreach ($data as $k => $v) { $data[$k] = $this->preserveEmptyObjects($v); } } return $data; } }
使用时在控制器中注入该自定义请求类即可:
use App\Http\Requests\RequestJsonOverride; publicpublic function store(RequestJsonOverride $request) { $emptyObject = $request->json('shouldBeEmptyObject'); // 保留空对象类型 }
内容的提问来源于stack exchange,提问作者Nicolas
相关产品推荐
相关产品推荐

