You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Serverpod 0.9.21示例项目调用接口返回400无错误信息问题

Serverpod 0.9.21自定义接口返回400错误排查与解决

问题背景

  • 基于Serverpod 0.9.21搭建后端,已将Flutter客户端地址改为http://10.0.2.2:8080/,解决模拟器SocketException问题,示例say hello功能正常
  • 自定义addProvince接口返回400错误,无errorMessage,数据库province表已创建且状态正常

已完成的配置与代码

1. Province协议定义(test_server包内)

class: Province
table: province
fields:
  name: String
  isEnabled: bool

2. ProvinceEndpoint实现

import 'package:serverpod/serverpod.dart';
import '../generated/protocol.dart';

class ProvinceEndpoint extends Endpoint {
  Future<bool> addProvince(Session session, Province province) async {
    await Province.insert(session, province);
    return true;
  }
}

3. 客户端main.dart代码

import 'package:back_client/back_client.dart';
import 'package:flutter/material.dart';
import 'package:serverpod_flutter/serverpod_flutter.dart';

var client = Client('http://10.0.2.2:8080/')
  ..connectivityMonitor = FlutterConnectivityMonitor();

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final _nameController = TextEditingController(text: "name1");
  String result = "here";

  addProvince() async {
    final province = Province(name: _nameController.text, isEnabled: true);
    client.province.addProvince(province).then((value) {
      if (value) {
        setState(() {
          result = "Done adding ${_nameController.text} province";
        });
      } else {
        result = "Nashod!";
      }
    }).catchError((onError) {
      final error = (onError is ServerpodClientException)
          ? "${onError.message} ${onError.statusCode}"
          : "Error ";
      setState(() {
        result = error;
      });
    }).whenComplete(() {
      print("done");
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Column(
        children: [
          TextField(
            controller: _nameController,
          ),
          Text(
            result,
            style: Theme.of(context).textTheme.headline3,
          )
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: addProvinces, // 存在方法名拼写错误
        child: const Icon(Icons.add),
      ),
    );
  }
}

排查与解决步骤

  1. 修正客户端方法名拼写错误
    客户端代码中FloatingActionButton的onPressed绑定的是addProvinces,但实际定义的方法是addProvince(多了末尾的s),修正为onPressed: addProvince,确保点击按钮能正确触发接口调用。

  2. 查看Serverpod服务端日志
    400错误的详细原因通常会输出在Serverpod的控制台日志中,重点关注:

    • 协议序列化/反序列化失败提示
    • 数据库插入时的约束错误(比如字段非空但传入空值)
    • Endpoint未正确注册的提示
  3. 检查协议字段可空性
    若数据库表要求name字段非空,需在协议中明确标记字段为必填:

    fields:
      name: String, required
      isEnabled: bool, required
    

    修改后重新执行serverpod generate并重启服务。

  4. 验证接口请求结构
    使用Postman或curl直接调用接口http://10.0.2.2:8080/api/province/addProvince,传入标准JSON参数:

    {
      "province": {
        "name": "test_province",
        "isEnabled": true
      }
    }
    

    根据返回的详细错误信息定位问题。

  5. 重新生成代码并重启服务
    确保serverpod generate执行无报错,生成的protocol.dart包含完整的Province类与客户端方法,之后重启Serverpod服务器避免缓存影响。


内容的提问来源于stack exchange,提问作者Kamran Akbary

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 09:30:57