Flutter HTTP包调用Laravel搜索API返回Null问题排查
Postman调用该API可正常返回结果,但使用Flutter HTTP包调用时返回Null,两端代码如下:
Laravel后端代码
public function search(Request $request) { try { $request->validate(['search' => ['max:15', 'required']]); $search = $request->input('search'); $answerSearch = Answer::where('title','like', '%'.$search.'%')->get(); return AnswersResource::collection($answerSearch); }catch(\Exception $e){ return response()->json(['status'=>false, 'msg'=> $e->getMessage()], 500); } }
Flutter前端调用代码
Future<List<AnswerData>> searchAnswers({required String search}) async { final response = await post( Uri.parse("$_url/search"), headers: <String, String>{ 'Content-Type': 'application/json; charset=UTF-8', }, body: jsonEncode(<String, String>{"search" : search}) ); final answers = answerFromJson(response.body); print("fdfsdfdsfdsf ${answers.data}"); return answers.data; }
1. Laravel未正确解析JSON请求体
Laravel的request()->input()默认优先解析表单格式(application/x-www-form-urlencoded)的参数,但Flutter发送的是application/json格式请求,此时input()无法正确获取JSON体中的参数,导致查询条件为空,返回空集合,最终Flutter解析后得到Null。
解决办法:
修改Laravel中参数获取方式,改用JSON解析方法:
// 替换原有的$search = $request->input('search'); $search = $request->json('search'); // 或者直接通过属性访问(Laravel会自动解析JSON体) $search = $request->search;
2. 模型资源返回结构与Flutter实体类不匹配
AnswersResource::collection()返回的JSON结构默认是{"data": [...]}的包裹格式,但如果Flutter的answerFromJson方法期望直接接收数组,或者实体类的字段映射错误,会导致解析后answers.data为Null。
解决办法:
- 先在Flutter中打印
response.body,确认后端返回的JSON结构; - 确保Flutter实体类与返回结构匹配,比如定义对应包裹结构的实体:
class AnswersResponse { final List<AnswerData> data; AnswersResponse({required this.data}); factory AnswersResponse.fromJson(Map<String, dynamic> json) { return AnswersResponse( data: List<AnswerData>.from(json['data'].map((x) => AnswerData.fromJson(x))), ); } }
- 修改解析代码:
final answers = AnswersResponse.fromJson(jsonDecode(response.body));
3. 请求验证失败未被正确处理
如果Flutter发送的参数不符合max:15规则,或者参数名拼写错误,Laravel的validate方法会抛出ValidationException,默认返回422状态码的错误JSON,但当前Laravel的catch块未针对性处理该异常,且Flutter端未检查响应状态码,直接解析错误JSON会导致解析失败,返回Null。
解决办法:
- Flutter端增加状态码检查:
if (response.statusCode == 200) { final answers = AnswersResponse.fromJson(jsonDecode(response.body)); return answers.data; } else if (response.statusCode == 422) { final errorData = jsonDecode(response.body); throw Exception('参数错误:${errorData['message']}'); } else { throw Exception('请求失败:${response.statusCode}'); }
- Laravel端优化异常捕获,明确返回验证错误:
catch(\Exception $e){ if ($e instanceof \Illuminate\Validation\ValidationException) { return response()->json([ 'status'=>false, 'msg'=> $e->validator->errors()->first() ], 422); } return response()->json(['status'=>false, 'msg'=> $e->getMessage()], 500); }
4. 跨域问题(移动端概率低)
若Flutter运行在Web环境,可能存在跨域限制,导致请求未正确发送;移动端一般无此问题,但可排查Laravel是否配置了CORS。
解决办法:
安装barryvdh/laravel-cors包,配置允许Flutter所在域名/端口的跨域请求。
内容的提问来源于stack exchange,提问作者Osama Mohammed

