首页 > 解决方案 > Flutter 应用 API POST 响应未返回

问题描述

我正在使用提交方法将数据发布到 REST 服务后端,并且保存方法调用此 POST 并等待来自后端的响应。

POST 的异步方法如下

Future<PetCreate> createThePet(data, apiUrl) async{
    var fullUrl = _baseUrl + apiUrl; // + await _getToken();
    final response = await http.post(fullUrl, body: jsonEncode(data), headers: _setHeaders());

    if(response.statusCode == 200){
      final String responseString = response.body;
      print(responseString);
      return petCreateFromJson(responseString);
    }else{
      return null;
    }
  }

这里响应即将到来,但是当我尝试将该 response.body 传递给字符串值“responseString”时,它会失败。print(responseString) 中途停止打印,'return petCreateFromJson(responseString);' 也没有被调用。

*** 数据模型 ***

PetCreate petCreateFromJson(String str) => PetCreate.fromJson(json.decode(str));

String petCreateToJson(PetCreate data) => json.encode(data.toJson());

class PetCreate {
  PetCreate({
    this.success,
    this.pet,
  });

  bool success;
  Pet pet;

  factory PetCreate.fromJson(Map<String, dynamic> json) => PetCreate(
    success: json["success"],
    pet: Pet.fromJson(json["pet"]),
  );

  Map<String, dynamic> toJson() => {
    "success": success,
    "pet": pet.toJson(),
  };
}

class Pet {
  Pet({
    this.id,
    this.activityLevelName,
    this.dailyAllowanceGuidelinesDetails,
    this.eatbone,
    this.idealWeight,
    this.image,
    this.name,
    this.nutrientGuidelineDetail,
    this.totalDailyCalories,
    this.weight,
    this.breed,
  });

  int id;
  String activityLevelName;
  List<DailyAllowanceGuidelinesDetail> dailyAllowanceGuidelinesDetails;
  bool eatbone;
  double idealWeight;
  Image image;
  String name;
  List<NutrientGuidelineDetail> nutrientGuidelineDetail;
  String totalDailyCalories;
  double weight;
  Breed breed;

  factory Pet.fromJson(Map<String, dynamic> json) => Pet(
    id: json["id"],
    activityLevelName: json["activity_level_name"],
    dailyAllowanceGuidelinesDetails: List<DailyAllowanceGuidelinesDetail>.from(json["daily_allowance_guidelines_details"].map((x) => DailyAllowanceGuidelinesDetail.fromJson(x))),
    eatbone: json["eatbone"],
    idealWeight: json["ideal_weight"].toDouble(),
    image: Image.fromJson(json["image"]),
    name: json["name"],
    nutrientGuidelineDetail: List<NutrientGuidelineDetail>.from(json["nutrient_guideline_detail"].map((x) => NutrientGuidelineDetail.fromJson(x))),
    totalDailyCalories: json["total_daily_calories"],
    weight: json["weight"].toDouble(),
    breed: Breed.fromJson(json["breed"]),
  );

  Map<String, dynamic> toJson() => {
    "id": id,
    "activity_level_name": activityLevelName,
    "daily_allowance_guidelines_details": List<dynamic>.from(dailyAllowanceGuidelinesDetails.map((x) => x.toJson())),
    "eatbone": eatbone,
    "ideal_weight": idealWeight,
    "image": image.toJson(),
    "name": name,
    "nutrient_guideline_detail": List<dynamic>.from(nutrientGuidelineDetail.map((x) => x.toJson())),
    "total_daily_calories": totalDailyCalories,
    "weight": weight,
    "breed": breed.toJson(),
  };
}

class Breed {
  Breed({
    this.id,
    this.creatorId,
    this.updaterId,
    this.deleterId,
    this.deletedAt,
    this.giant,
    this.name,
    this.createdAt,
    this.updatedAt,
  });

  int id;
  dynamic creatorId;
  dynamic updaterId;
  dynamic deleterId;
  dynamic deletedAt;
  dynamic giant;
  String name;
  DateTime createdAt;
  DateTime updatedAt;

  factory Breed.fromJson(Map<String, dynamic> json) => Breed(
    id: json["id"],
    creatorId: json["creator_id"],
    updaterId: json["updater_id"],
    deleterId: json["deleter_id"],
    deletedAt: json["deleted_at"],
    giant: json["giant"],
    name: json["name"],
    createdAt: DateTime.parse(json["created_at"]),
    updatedAt: DateTime.parse(json["updated_at"]),
  );

  Map<String, dynamic> toJson() => {
    "id": id,
    "creator_id": creatorId,
    "updater_id": updaterId,
    "deleter_id": deleterId,
    "deleted_at": deletedAt,
    "giant": giant,
    "name": name,
    "created_at": createdAt.toIso8601String(),
    "updated_at": updatedAt.toIso8601String(),
  };
}

class DailyAllowanceGuidelinesDetail {
  DailyAllowanceGuidelinesDetail({
    this.name,
    this.bones,
    this.percentage,
  });

  String name;
  bool bones;
  int percentage;

  factory DailyAllowanceGuidelinesDetail.fromJson(Map<String, dynamic> json) => DailyAllowanceGuidelinesDetail(
    name: json["name"],
    bones: json["bones"],
    percentage: json["percentage"],
  );

  Map<String, dynamic> toJson() => {
    "name": name,
    "bones": bones,
    "percentage": percentage,
  };
}

class Image {
  Image({
    this.url,
    this.thumb,
  });

  dynamic url;
  Thumb thumb;

  factory Image.fromJson(Map<String, dynamic> json) => Image(
    url: json["url"],
    thumb: Thumb.fromJson(json["thumb"]),
  );

  Map<String, dynamic> toJson() => {
    "url": url,
    "thumb": thumb.toJson(),
  };
}

class Thumb {
  Thumb({
    this.url,
  });

  dynamic url;

  factory Thumb.fromJson(Map<String, dynamic> json) => Thumb(
    url: json["url"],
  );

  Map<String, dynamic> toJson() => {
    "url": url,
  };
}

class NutrientGuidelineDetail {
  NutrientGuidelineDetail({
    this.name,
    this.amount,
    this.unit,
  });

  String name;
  double amount;
  Unit unit;

  factory NutrientGuidelineDetail.fromJson(Map<String, dynamic> json) => NutrientGuidelineDetail(
    name: json["name"],
    amount: json["amount"].toDouble(),
    unit: unitValues.map[json["unit"]],
  );

  Map<String, dynamic> toJson() => {
    "name": name,
    "amount": amount,
    "unit": unitValues.reverse[unit],
  };
}

enum Unit { G, RATIO, MG, MCG }

final unitValues = EnumValues({
  "g": Unit.G,
  "mcg": Unit.MCG,
  "mg": Unit.MG,
  "ratio": Unit.RATIO
});

class EnumValues<T> {
  Map<String, T> map;
  Map<T, String> reverseMap;

  EnumValues(this.map);

  Map<T, String> get reverse {
    if (reverseMap == null) {
      reverseMap = map.map((k, v) => new MapEntry(v, k));
    }
    return reverseMap;
  }
}

来自 API 的示例响应如下所示

{
  "success": true,
  "pet": {
    "id": 31,
    "activity_level_name": "Low Activity (<1hr/day)",
    "daily_allowance_guidelines_details": [
      {
        "name": "Muscle Meat",
        "bones": true,
        "percentage": 60
      },
      {
        "name": "Organ Meat",
        "bones": false,
        "percentage": 10
      },
      {
        "name": "Fruit and Veg",
        "bones": false,
        "percentage": 20
      },
      {
        "name": "Bone",
        "bones": true,
        "percentage": 10
      }
    ],
    "eatbone": true,
    "ideal_weight": 4.4,
    "image": {
      "url": null,
      "thumb": {
        "url": null
      }
    },
    "name": "petsy",
    "nutrient_guideline_detail": [
      {
        "name": "Protein",
        "amount": 12.54,
        "unit": "g"
      },
      {
        "name": "Crude fat",
        "amount": 3.85,
        "unit": "g"
      },
      {
        "name": "Calcium/Phosphorus ratio",
        "amount": 0.56,
        "unit": "ratio"
      },
      {
        "name": "Omega-3/6 ratio",
        "amount": 0.07,
        "unit": "ratio"
      },
      {
        "name": "Omega-6",
        "amount": 0.78,
        "unit": "g"
      },
      {
        "name": "Omega-3 excl. ALA and SDA",
        "amount": 0.03,
        "unit": "g"
      },
      {
        "name": "Calcium",
        "amount": 0.35,
        "unit": "g"
      },
      {
        "name": "Phosphorus",
        "amount": 0.28,
        "unit": "g"
      },
      {
        "name": "Potassium",
        "amount": 0.42,
        "unit": "g"
      },
      {
        "name": "Sodium (Na)",
        "amount": 0.06,
        "unit": "mg"
      },
      {
        "name": "Magnesium",
        "amount": 0.04,
        "unit": "mg"
      },
      {
        "name": "Iron",
        "amount": 2.79,
        "unit": "mg"
      },
      {
        "name": "Copper",
        "amount": 0.51,
        "unit": "mg"
      },
      {
        "name": "Manganese",
        "amount": 0.35,
        "unit": "mg"
      },
      {
        "name": "Zinc (Zn)",
        "amount": 5.57,
        "unit": "mg"
      },
      {
        "name": "Iodine",
        "amount": 69.68,
        "unit": "mcg"
      },
      {
        "name": "Selenium",
        "amount": 0.02,
        "unit": "mcg"
      },
      {
        "name": "Vitamin A",
        "amount": 104.52,
        "unit": "mcg"
      },
      {
        "name": "Vitamin D",
        "amount": 0.86,
        "unit": "mcg"
      },
      {
        "name": "Vitamin E",
        "amount": 3.14,
        "unit": "mg"
      },
      {
        "name": "Thiamin (B1)",
        "amount": 0.16,
        "unit": "mg"
      },
      {
        "name": "Riboflavin (B2)",
        "amount": 0.36,
        "unit": "mg"
      },
      {
        "name": "Niacin (B3)",
        "amount": 0.95,
        "unit": "mg"
      },
      {
        "name": "Pantothenic acid (B5)",
        "amount": 0.84,
        "unit": "mg"
      },
      {
        "name": "Folate",
        "amount": 15.05,
        "unit": "mcg"
      },
      {
        "name": "Choline",
        "amount": 94.76,
        "unit": "mg"
      },
      {
        "name": "Vitamin C",
        "amount": 0,
        "unit": "mg"
      }
    ],
    "total_daily_calories": "278.72",
    "weight": 4.2,
    "breed": {
      "id": 1,
      "creator_id": null,
      "updater_id": null,
      "deleter_id": null,
      "deleted_at": null,
      "giant": null,
      "name": "Abyssinian San Terrier",
      "created_at": "2020-09-24T16:41:36.111+09:30",
      "updated_at": "2020-09-24T16:41:36.111+09:30"
    }
  }
}

当我尝试做

Future<PetCreate> createThePet(data, apiUrl) async{
    var fullUrl = _baseUrl + apiUrl; // + await _getToken();
    final response = await http.post(fullUrl, body: jsonEncode(data), headers: _setHeaders());

    if(response.statusCode == 200){
      var responseString = response.body;
      //print(responseString);
      return null; //petCreateFromJson(responseString);
    }else{
      return null;
    }
  }

代码执行

savePetData(BuildContext ctx) async {
//dogData here
final PetCreate pet = await CallApi().createThePet(dogData, 'pets/create');
    setState(() {
      _pet = pet;
    });

      print('///////////////////////// success //////////////////////////');
    if (_pet.success) {
      petPrefs = await SharedPreferences.getInstance();
      petPrefs.setString('pet_image', _pet.pet.image.thumb.url);

等等 。如果我按照我提到的那样运行代码而不进行更改,它会在此处停止'final PetCreate pet = await CallApi().createThePet(dogData,' 并再次跳转到方法调用'savePetData(BuildContext ctx)'

有人可以帮我弄清楚这里发生了什么,我该怎么办?

标签: jsonrestflutter

解决方案


await在调用之前使用savePetData(),以便等待函数执行完成。

Future<void> _handleSubmit(BuildContext context) async {
    setState(() {
      _isLoading = true;
    });
    LoadingDialog.showLoadingDialog(context, _petFormKey);
    await savePetData();
    setState(() {
      _isLoading = false;
    });
  }

推荐阅读