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

Flutter调用HAPIBOOK API时Map转List类型不匹配报错排查

问题原因

核心错误是接口返回结构和解析逻辑不匹配,和你写的authors字段转换逻辑无关:

  • 你当前调用的/book/{书籍ID}接口,返回值是{}包裹的单本图书Map对象,不是[]包裹的图书列表数组,你贴的返回JSON结构也能验证这一点
  • 代码里先把响应体解析成了Map类型,却直接传给了要求入参为List的hapiBookfromsnapshot方法,强行把Map类型传给List类型参数,直接触发你看到的类型匹配异常
  • 额外存在潜在风险:模型类中rating、pages字段定义为int类型,如果接口返回字符串格式的数字,会触发新的类型报错,解析时需要做类型兜底处理
修复方案

根据接口实际返回结构调整解析逻辑,单对象接口走单对象解析方法,列表接口再走列表解析方法,不要混用。

修正API调用逻辑

import 'dart:convert';

import 'package:fluttrapi2/models/hapi_book_model.dart';
import 'package:http/http.dart' as http;

class FetchApi {
  // 当前单本查询接口返回单个图书对象,返回值调整为HapiBook?
  static Future<HapiBook?> fetchSingleBook() async {
    var url = Uri.https('hapi-books.p.rapidapi.com', '/book/56597885');
    final res = await http.get(url, headers: {
      'X-RapidAPI-Key': '替换为你自己的有效RapidAPI密钥',
      'X-RapidAPI-Host': 'hapi-books.p.rapidapi.com'
    });
    if (res.statusCode == 200) {
      Map<String, dynamic> json = jsonDecode(res.body);
      // 单Map对象直接调用fromJson构造解析,不要传列表解析方法
      return HapiBook.fromJson(json);
    }
    return null;
  }

  // 后续如果调用榜单、搜索类返回图书数组的接口,用这个方法
  static Future<List<HapiBook>?> fetchBookList() async {
    // 替换为实际返回数组结构的接口路径
    var url = Uri.https('hapi-books.p.rapidapi.com', '/替换为列表接口路径');
    final res = await http.get(url, headers: {
      'X-RapidAPI-Key': '替换为你自己的有效RapidAPI密钥',
      'X-RapidAPI-Host': 'hapi-books.p.rapidapi.com'
    });
    if (res.statusCode == 200) {
      // 确认响应最外层是[]数组结构时,再转List传给列表解析方法
      List<dynamic> jsonList = jsonDecode(res.body);
      return HapiBook.hapiBookfromsnapshot(jsonList);
    }
    return null;
  }
}

优化模型类增加类型兜底

避免接口返回字段类型和预期不一致时抛出异常:

import 'dart:convert';

HapiBook hapiBookFromJson(String str) => HapiBook.fromJson(json.decode(str));

String hapiBookToJson(HapiBook data) => json.encode(data.toJson());

class HapiBook {
  HapiBook({
    required this.bookId,
    required this.name,
    required this.cover,
    required this.url,
    required this.authors,
    required this.rating,
    required this.pages,
    required this.publishedDate,
    required this.synopsis,
  });

  int bookId;
  String name;
  String cover;
  String url;
  List<String> authors;
  int rating;
  int pages;
  String publishedDate;
  String synopsis;

  factory HapiBook.fromJson(Map<String, dynamic> json) => HapiBook(
        bookId: json["book_id"] is int ? json["book_id"] : int.tryParse(json["book_id"].toString()) ?? 0,
        name: json["name"]?.toString() ?? '',
        cover: json["cover"]?.toString() ?? '',
        url: json["url"]?.toString() ?? '',
        authors: json["authors"] == null ? [] : List<String>.from(json["authors"].map((x) => x.toString())),
        rating: json["rating"] is int ? json["rating"] : int.tryParse(json["rating"].toString()) ?? 0,
        pages: json["pages"] is int ? json["pages"] : int.tryParse(json["pages"].toString()) ?? 0,
        publishedDate: json["published_date"]?.toString() ?? '',
        synopsis: json["synopsis"]?.toString() ?? '',
      );

  static List<HapiBook> hapiBookfromsnapshot(List snapshot) {
    return snapshot.map((data) {
      return HapiBook.fromJson(data as Map<String, dynamic>);
    }).toList();
  }

  Map<String, dynamic> toJson() => {
        "book_id": bookId,
        "name": name,
        "cover": cover,
        "url": url,
        "authors": List<dynamic>.from(authors.map((x) => x)),
        "rating": rating,
        "pages": pages,
        "published_date": publishedDate,
        "synopsis": synopsis,
      };
}

解析接口前先确认响应最外层结构:最外层为{}对应单对象解析逻辑,最外层为[]对应列表解析逻辑,二者不要混用,就能避免绝大多数这类类型转换错误。

内容的提问来源于stack exchange,提问作者DAni M

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 19:42:25