flutter dio is returning DioErrorType.unknown

huangapple go评论78阅读模式
英文:

flutter dio is returning DioErrorType.unknown

问题

I see you have provided a code snippet in English. Here's the translation of the code:

我正在一个项目中使用干净的架构,使用dio作为HTTP包,并添加了pretty DioLogger作为dio拦截器来记录请求和响应

pretty dio logger正在记录200 ok的响应,但是我得到的不是正确的dio响应,而是得到了dioErrorType.unknown,我无法访问实际的响应,这个错误的原因是什么?

我创建了一个只包含有问题的代码的测试项目,这里是dio工厂类

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';

class DioFactory {
Dio getDio() {
Dio dio = Dio();

Map<String, String> headers = {
  'content-type': 'application/json',
  'accept': 'application/json',
};
dio.options = BaseOptions(
  baseUrl: 'https://1rkj9.wiremockapi.cloud/',
  headers: headers,
  sendTimeout: const Duration(milliseconds: 60 * 1000),
  receiveTimeout: const Duration(milliseconds: 60 * 1000),
);

if (!kReleaseMode) {
  dio.interceptors.add(
    PrettyDioLogger(
      requestHeader: true,
      requestBody: true,
      responseHeader: true,
    ),
  );
}
return dio;

}
}


我使用了retrofit generator生成请求,这是我的app客户端类:

import 'package:dio/dio.dart';
import 'package:retrofit/retrofit.dart';

import '../responses/responses.dart';

part 'app_api.g.dart';

@RestApi(baseUrl: 'https://1rkj9.wiremockapi.cloud/')
abstract class AppServiceClient {
factory AppServiceClient({required Dio dio, String? baseURL}) =>
_AppServiceClient(dio);

@POST('/customer/forgotPassword')
Future forgotPassword(@Field('email') String email);
}


这是生成的app:

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'app_api.dart';

// **************************************************************************
// RetrofitGenerator
// **************************************************************************

// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers

class _AppServiceClient implements AppServiceClient {
_AppServiceClient(
this._dio, {
this.baseUrl,
}) {
baseUrl ??= 'https://1rkj9.wiremockapi.cloud/';
}

final Dio _dio;

String? baseUrl;

@override
Future forgotPassword(String email) async {
const _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
final _data = {'email': email};
final _result = await _dio.fetch<Map<String, dynamic>>(
_setStreamType(Options(
method: 'POST',
headers: _headers,
extra: _extra,
)
.compose(
_dio.options,
'/customer/forgotPassword',
queryParameters: queryParameters,
data: _data,
)
.copyWith(baseUrl: baseUrl ?? _dio.options.baseUrl)));
final value = ForgotPasswordResponse.fromJson(_result.data!);
return value;
}

RequestOptions _setStreamType(RequestOptions requestOptions) {
if (T != dynamic &&
!(requestOptions.responseType == ResponseType.bytes ||
requestOptions.responseType == ResponseType.stream)) {
if (T == String) {
requestOptions.responseType = ResponseType.plain;
} else {
requestOptions.responseType = ResponseType.json;
}
}
return requestOptions;
}
}


我使用了json_annotation包生成响应,这是响应文件:

import 'package:json_annotation/json_annotation.dart';

part 'responses.g.dart';

@JsonSerializable()
class BaseResponse {
@JsonKey(name: "status")
int? status;

@JsonKey(name: "message")
String? message;
}

@JsonSerializable()
class ForgotPasswordResponse extends BaseResponse {
@JsonKey(name: "support")
String? support;

ForgotPasswordResponse({required this.support});

factory ForgotPasswordResponse.fromJson(Map<String, dynamic> json) =>
_$ForgotPasswordResponseFromJson(json);

Map<String, dynamic> toJson() => _$ForgotPasswordResponseToJson(this);
}


这是生成的响应文件:

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'responses.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

BaseResponse _$BaseResponseFromJson(Map<String, dynamic> json) => BaseResponse()
..status = json['status'] as int?
..message = json['message'] as String?;

Map<String, dynamic> _$BaseResponseToJson(BaseResponse instance) =>
<String, dynamic>{
'status': instance.status,
'message': instance.message,
};

ForgotPasswordResponse _$ForgotPasswordResponseFromJson(
Map<String, dynamic> json) =>
ForgotPasswordResponse(
support: json['support'] as String?,
)
..status = json['status'] as int?
..message = json['message'] as String?;

Map<String, dynamic> _$ForgotPasswordResponseToJson(
ForgotPasswordResponse instance) =>
<String, dynamic>{
'status': instance.status,
'message': instance.message,
'support': instance.support,
};


最后,这是主文件:

import 'dart:developer';

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:testing_app/network/app_api.dart';

import 'network/dio_factory.dart';

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

class MyApp extends StatelessWidget {
final AppServiceClient appServiceClient =
AppServiceClient(dio: DioFactory().getDio());

MyApp({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('test app'),
),
body: Center(
child: TextButton(
onPressed: () async {
try {
final response =
await appServiceClient.forgotPassword('abc@gmail.com');
log('response code: ${response.status}');
} catch (error) {
if (error is DioError) {
log('error type: ${error.type}');
}
}
},
child: Text('start dio post request'),
),
)),
);
}
}


如果您需要更多的帮助或有其他问题,请告诉我。

<details>
<summary>英文:</summary>

I&#39;m using clean architecture on a project and using dio as http package and I&#39;ve added pretty DioLogger as a dio inceptor to log requests and response.

the pretty dio logger is logging a reponse of 200 ok but I&#39;m getting instead of a correct dio response I&#39;m getting dioErrorType.unknown and I&#39;m unable to reach the actual response, what could be the cause of this error?

I&#39;ve made a test project with only the faulty code, here&#39;s the dio factory class:

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';

class DioFactory {
Dio getDio() {
Dio dio = Dio();

Map&lt;String, String&gt; headers = {
  &#39;content-type&#39;: &#39;application/json&#39;,
  &#39;accept&#39;: &#39;application/json&#39;,
};
dio.options = BaseOptions(
  baseUrl: &#39;https://1rkj9.wiremockapi.cloud/&#39;,
  headers: headers,
  sendTimeout: const Duration(milliseconds: 60 * 1000),
  receiveTimeout: const Duration(milliseconds: 60 * 1000),
);

if (!kReleaseMode) {
  dio.interceptors.add(
    PrettyDioLogger(
      requestHeader: true,
      requestBody: true,
      responseHeader: true,
    ),
  );
}
return dio;

}
}

I&#39;ve used retrofit generator to generate the request, here is my app client class:

import 'package:dio/dio.dart';
import 'package:retrofit/retrofit.dart';

import '../responses/responses.dart';

part 'app_api.g.dart';

@RestApi(baseUrl: 'https://1rkj9.wiremockapi.cloud/')
abstract class AppServiceClient {
factory AppServiceClient({required Dio dio, String? baseURL}) =>
_AppServiceClient(dio);

@POST('/customer/forgotPassword')
Future<ForgotPasswordResponse> forgotPassword(@Field('email') String email);
}

and here&#39;s the generated app:

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'app_api.dart';

// **************************************************************************
// RetrofitGenerator
// **************************************************************************

// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers

class _AppServiceClient implements AppServiceClient {
_AppServiceClient(
this._dio, {
this.baseUrl,
}) {
baseUrl ??= 'https://1rkj9.wiremockapi.cloud/';
}

final Dio _dio;

String? baseUrl;

@override
Future<ForgotPasswordResponse> forgotPassword(String email) async {
const _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
final _data = {'email': email};
final _result = await _dio.fetch<Map<String, dynamic>>(
_setStreamType<ForgotPasswordResponse>(Options(
method: 'POST',
headers: _headers,
extra: _extra,
)
.compose(
_dio.options,
'/customer/forgotPassword',
queryParameters: queryParameters,
data: _data,
)
.copyWith(baseUrl: baseUrl ?? _dio.options.baseUrl)));
final value = ForgotPasswordResponse.fromJson(_result.data!);
return value;
}

RequestOptions _setStreamType<T>(RequestOptions requestOptions) {
if (T != dynamic &&
!(requestOptions.responseType == ResponseType.bytes ||
requestOptions.responseType == ResponseType.stream)) {
if (T == String) {
requestOptions.responseType = ResponseType.plain;
} else {
requestOptions.responseType = ResponseType.json;
}
}
return requestOptions;
}
}


I&#39;ve used json_annotation package to generate the repsonses, here&#39;s the response file:

import 'package:json_annotation/json_annotation.dart';

part 'responses.g.dart';

@JsonSerializable()
class BaseResponse {
@JsonKey(name: "status")
int? status;

@JsonKey(name: "message")
String? message;
}

@JsonSerializable()
class ForgotPasswordResponse extends BaseResponse {
@JsonKey(name: "support")
String? support;

ForgotPasswordResponse({required this.support});

factory ForgotPasswordResponse.fromJson(Map<String, dynamic> json) =>
_$ForgotPasswordResponseFromJson(json);

Map<String, dynamic> toJson() => _$ForgotPasswordResponseToJson(this);
}

and here&#39;s the generated response file:

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'responses.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

BaseResponse _$BaseResponseFromJson(Map<String, dynamic> json) => BaseResponse()
..status = json['status'] as int?
..message = json['message'] as String?;

Map<String, dynamic> _$BaseResponseToJson(BaseResponse instance) =>
<String, dynamic>{
'status': instance.status,
'message': instance.message,
};

ForgotPasswordResponse _$ForgotPasswordResponseFromJson(
Map<String, dynamic> json) =>
ForgotPasswordResponse(
support: json['support'] as String?,
)
..status = json['status'] as int?
..message = json['message'] as String?;

Map<String, dynamic> _$ForgotPasswordResponseToJson(
ForgotPasswordResponse instance) =>
<String, dynamic>{
'status': instance.status,
'message': instance.message,
'support': instance.support,
};


and finally this is the main file:

import 'dart:developer';

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:testing_app/network/app_api.dart';

import 'network/dio_factory.dart';

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

class MyApp extends StatelessWidget {
final AppServiceClient appServiceClient =
AppServiceClient(dio: DioFactory().getDio());

MyApp({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('test app'),
),
body: Center(
child: TextButton(
onPressed: () async {
try {
final response =
await appServiceClient.forgotPassword('abc@gmail.com');
log('response code: ${response.status}');
} catch (error) {
if (error is DioError) {
log('error type: ${error.type}');
}
}
},
child: Text('start dio post request'),
),
)),
);
}
}


</details>


# 答案1
**得分**: 0

问题是我在我使用的mockAPI响应头中没有添加"Content-Type":"application/json"。

<details>
<summary>英文:</summary>

The problem was that I didn&#39;t add &quot;Content-Type&quot;:&quot;application/json&quot; in the header of the response in the mockAPI that I&#39;m using 

</details>



huangapple
  • 本文由 发表于 2023年5月11日 05:03:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76222537.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定