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

Flutter使用HTTP Get获取数据库数据报错,求可运行示例

问题:Flutter HTTP Get请求报错:type 'String' is not a subtype of type 'int' of 'index'

执行Flutter的HTTP Get请求从数据库获取数据时,出现以下错误:

E/flutter (15407): [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: type 'String' is not a subtype of type 'int' of 'index'

我的代码:

// ignore_for_file: no_leading_underscores_for_local_identifiers, prefer_typing_uninitialized_variables

import 'dart:convert';

import 'package:apetit_project/models/app_user.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import '../models/auth_form_data.dart';
import 'package:http/http.dart' as http;

class AuthForm extends StatefulWidget {
  final void Function(AuthFormData) onSubmit;

  const AuthForm({
    Key? key,
    required widget.onSubmit,
  }) : super(key: key);

  @override
  State<AuthForm> createState() => _AuthFormState();
}

class _AuthFormState extends State<AuthForm> {
  TextEditingController _emailController = TextEditingController();
  TextEditingController _passwordController = TextEditingController();
  final _formKey = GlobalKey<FormState>();
  final _formData = AuthFormData();
  String _teste = '[]';
  final _url = 'http://172.16.30.120:8080/ords/apiteste/integrafoods/users';

  @override
  void dispose() {
    _emailController.dispose();
    _passwordController.dispose();
    super.dispose();
  }

  bool isLogin = true;
  late String title;
  late String actionButton;
  late String toggleButton;

  void _submit() {
    final isValid = _formKey.currentState?.validate() ?? false;
    if (!isValid) return;

    widget.onSubmit(_formData);
  }

  Future<void> _loadUsers() async {
    final response = await http.get(Uri.parse(_url));
    Map<String, dynamic> data = jsonDecode(response.body);
    data.forEach(
      (userId, userData) {
        _teste = userData['nome'];
      },
    );
    print(_teste);

    // $_url/${newComment.comment}
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        decoration: const BoxDecoration(
          image: DecorationImage(
            image: AssetImage('assets/images/Login.png'),
            fit: BoxFit.cover,
            alignment: Alignment.center,
          ),
        ),
        child: Container(
          margin: const EdgeInsets.only(bottom: 30),
          child: Padding(
            padding: const EdgeInsets.all(20),
            child: Form(
              key: _formKey,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.end,
                children: [
                  if (_formData.isSignup)
                    TextFormField(
                      key: const ValueKey('Nome'),
                      initialValue: _formData.name,
                      onChanged: (name) => _formData.name = name,
                      decoration: InputDecoration(
                        enabledBorder: OutlineInputBorder(
                            borderSide: const BorderSide(color: Colors.black),
                            borderRadius: BorderRadius.circular(30)),
                        focusedBorder: OutlineInputBorder(
                            borderSide: const BorderSide(color: Colors.black),
                            borderRadius: BorderRadius.circular(30)),
                        focusedErrorBorder: OutlineInputBorder(
                            borderSide: const BorderSide(color: Colors.black),
                            borderRadius: BorderRadius.circular(30)),
                        labelText: 'Nome',
                        labelStyle: const TextStyle(color: Colors.black),
                      ),
                      keyboardType: TextInputType.emailAddress,
                    ),
                  if (_formData.isLogin)
                    TextFormField(
                      // controller: _emailController,
                      key: const ValueKey('Email'),
                      initialValue: _formData.email,
                      onChanged: (email) => _formData.email = email,
                      decoration: InputDecoration(
                        enabledBorder: OutlineInputBorder(
                            borderSide: const BorderSide(color: Colors.black),
                            borderRadius: BorderRadius.circular(30)),
                        focusedBorder: OutlineInputBorder(
                            borderSide: const BorderSide(color: Colors.black),
                            borderRadius: BorderRadius.circular(30)),
                        focusedErrorBorder: OutlineInputBorder(
                            borderSide: const BorderSide(color: Colors.black),
                            borderRadius: BorderRadius.circular(30)),
                        prefixIcon: Image.asset(
                          'assets/images/email_icon.png',
                          scale: 6,
                          color: Colors.black,
                        ),
                        labelText: 'Email',
                        labelStyle: const TextStyle(color: Colors.black),
                      ),
                      validator: (_email) {
                        final email = _email ?? '';
                        if (!email.contains('@')) {
                          return 'E-mail informado não é válido.';
                        }
                        return null;
                      },
                      keyboardType: TextInputType.emailAddress,
                    ),
                  const SizedBox(
                    height: 20,
                  ),
                  if (_formData.isLogin)
                    TextFormField(
                      // controller: _passwordController,
                      key: const ValueKey('password'),
                      initialValue: _formData.password,
                      onChanged: (password) => _formData.password = password,
                      style: const TextStyle(color: Colors.black),
                      obscureText: true,
                      decoration: InputDecoration(
                          enabledBorder: OutlineInputBorder(
                              borderSide: const BorderSide(color: Colors.black),
                              borderRadius: BorderRadius.circular(30)),
                          focusedBorder: OutlineInputBorder(
                              borderSide: const BorderSide(color: Colors.black),
                              borderRadius: BorderRadius.circular(30)),
                          errorBorder: OutlineInputBorder(
                              borderSide: const BorderSide(color: Colors.black),
                              borderRadius: BorderRadius.circular(30)),
                          focusedErrorBorder: OutlineInputBorder(
                              borderSide: const BorderSide(color: Colors.black),
                              borderRadius: BorderRadius.circular(30)),
                          prefixIcon: Padding(
                            padding: const EdgeInsets.only(left: 18, right: 18),
                            child: Image.asset(
                              'assets/images/password_icon.png',
                              scale: 6,
                              color: Colors.black,
                            ),
                          ),
                          labelText: 'Senha',
                          labelStyle: const TextStyle(color: Colors.black)),
                      validator: (_password) {
                        final password = _password ?? '';
                        if (password.length < 6) {
                          return 'Senha deve ter no mínimo 6 caracteres';
                        }
                        return null;
                      },
                    ),
                  const SizedBox(
                    height: 20,
                  ),
                  SizedBox(
                    width: double.infinity,
                    child: ElevatedButton(
                      // onPressed: _signInUser,
                      onPressed: _loadUsers,
                      style: ButtonStyle(
                        shape: MaterialStateProperty.all(RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(30),
                        )),
                        padding:
                            MaterialStateProperty.all(const EdgeInsets.all(15)),
                        backgroundColor: MaterialStateProperty.all(
                            Theme.of(context).colorScheme.secondary),
                      ),
                      child: Text(
                        _formData.isLogin ? 'Entrar' : 'Cadastrar',
                        style: const TextStyle(
                            color: Colors.black,
                            fontFamily: 'Raleway',
                            fontWeight: FontWeight.bold),
                      ),
                    ),
                  ),
                  TextButton(
                    onPressed: () {
                      setState(() {
                        _formData.toggleAuthMode();
                      });
                    },
                    child: Text(
                      _formData.isLogin
                          ? 'Criar uma nova conta?'
                          : 'Já possui conta?',
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }

  Future _signInUser() async {
    await FirebaseAuth.instance.signInWithEmailAndPassword(
      email: _emailController.text,
      password: _passwordController.text,
    );
  }
}

接口返回的JSON数据:

{
    "items": [
        {
            "id": 1,
            "login": "1234567",
            "nome": "Ricardo",
            "situacao": "A",
            "telefone": "(14) 99797-5621",
            "senha": "124578",
            "dt_inclusao": null,
            "usu_inclusao": null,
            "dt_alteracao": null,
            "usu_alteracao": null
        }
    ],
    "hasMore": false,
    "limit": 25,
    "offset": 0,
    "count": 1,
    "links": [
        {
            "rel": "self",
            "href": "http://172.16.30.120:8080/ords/apiteste/integrafoods/users"
        },
        {
            "rel": "describedby",
            "href": "http://172.16.30.120:8080/ords/apiteste/metadata-catalog/integrafoods/item"
        },
        {
            "rel": "first",
            "href": "http://172.16.30.120:8080/ords/apiteste/integrafoods/users"
        }
    ]
}

需要获取可运行的示例,理解问题并解决错误。


解决方法

错误原因

报错的核心问题在于_loadUsers方法中的数据解析逻辑错误:

  • 接口返回的JSON中,用户数据嵌套在items数组里,而你直接遍历整个顶层Map,当遍历到hasMore、limit等非数组类型的字段时,尝试用userData['nome']访问字符串/数值类型的value,就会抛出String is not a subtype of int的错误(因为这些value不是Map,用[]索引时会把字符串当成int索引来处理)。

修复后的_loadUsers方法

Future<void> _loadUsers() async {
  final response = await http.get(Uri.parse(_url));
  Map<String, dynamic> data = jsonDecode(response.body);
  
  // 先取出items数组,再遍历其中的用户对象
  List<dynamic> users = data['items'];
  for (var userData in users) {
    _teste = userData['nome'];
    print(_teste); // 会打印出"Ricardo"
  }
}

完整可运行的修改后代码

只需要替换原代码中的_loadUsers方法即可,其余代码保持不变。如果需要增加错误处理和UI更新,可使用以下版本:

Future<void> _loadUsers() async {
  final response = await http.get(Uri.parse(_url));
  if (response.statusCode == 200) {
    Map<String, dynamic> data = jsonDecode(response.body);
    List<dynamic> users = data['items'];
    
    // 遍历所有用户并打印信息
    for (var user in users) {
      print("用户名: ${user['nome']}, 登录名: ${user['login']}");
      _teste = user['nome']; // 保存最后一个用户的名字到_teste
    }
    
    setState(() {}); // 如果需要更新UI,调用setState刷新
  } else {
    print("请求失败,状态码: ${response.statusCode}");
  }
}

额外优化建议

  1. 强类型解析:定义用户模型类,将JSON数据解析为强类型对象,提升代码可读性和维护性

    // 假设AppUser类定义如下
    class AppUser {
      final int id;
      final String login;
      final String nome;
      final String situacao;
      final String telefone;
    
      AppUser({
        required this.id,
        required this.login,
        required this.nome,
        required this.situacao,
        required this.telefone,
      });
    
      factory AppUser.fromJson(Map<String, dynamic> json) {
        return AppUser(
          id: json['id'],
          login: json['login'],
          nome: json['nome'],
          situacao: json['situacao'],
          telefone: json['telefone'],
        );
      }
    }
    

    修改解析逻辑:

    List<AppUser> userList = users.map((user) => AppUser.fromJson(user)).toList();
    
  2. 异常捕获:添加try-catch块处理网络请求和JSON解析中的异常,避免崩溃


内容的提问来源于stack exchange,提问作者pedro.curti

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 01:06:41