如何在 Dart 中为 MultiPart 请求设置超时?
Posted
技术标签:
【中文标题】如何在 Dart 中为 MultiPart 请求设置超时?【英文标题】:How to set Timeout for MultiPart Request in Dart? 【发布时间】:2020-02-03 10:10:33 【问题描述】:这是我的MultiPartRequest
代码
var request =
http.MultipartRequest("POST", Uri.parse(EMPLOYEE_PUNCH_IN_URL));
request.fields['uid'] = userId;
request.fields['location'] = location;
request.fields['punchin_time'] = punchInTime;
request.fields['punchin_location_name'] = address;
var multiPartFile = await http.MultipartFile.fromPath(
"photo", imageFile.path,
contentType: MediaType("image", "$extension"));
request.files.add(multiPartFile);
http.StreamedResponse response = await request.send();
var responseByteArray = await response.stream.toBytes();
employeePunchInModel = standardSerializers.deserializeWith(
EmployeePunchInModel.serializer,
json.decode(utf8.decode(responseByteArray)));
......
我知道如何将超时设置为正常的 http 请求。我已经关注了这个链接
Set timeout for HTTPClient get() request
我尝试通过以下方式添加超时功能,但它不起作用并且我的请求已完成
1.
var multiPartFile = await http.MultipartFile.fromPath(
"photo", imageFile.path,
contentType: MediaType("image", "$extension")).timeout(const Duration(seconds: 1));
2.
http.StreamedResponse response = await request.send().timeout(const Duration(seconds: 1));
3.
var responseByteArray = await response.stream.toBytes().timeout(const Duration(seconds: 15));
但上述超时都不起作用。
【问题讨论】:
选项 1 设置从文件构建多部分请求的超时。所以如果例如。它是一个需要很长时间才能读取的大文件或设备 IO 很慢,它会在构建请求之前超时。选项 2 设置接收响应标头的超时。这通常意味着服务器已经接收并处理了整个请求,并且已经响应了一个状态码。选项 3 设置接收其余响应的超时时间 - 响应正文。你到底想设置什么超时?? @Ovidiu 我想为发送到服务器的 http 请求设置超时 那是选项 2。如果服务器在给定时间内没有接收、读取和处理整个请求,然后回复返回给应用程序的 HTTP 状态代码,则将被视为超时。 这是关于 C# 的吗? @Momoro 关于 Dart 语言和 Flutter 框架 【参考方案1】:使用http package,这是我的方法:
-
创建我们将用于
onTimeOut
回调的流式响应
StreamedResponse timeOutResponse(
@required String httpMethod,
@required dynamic error,
@required String url,
)
Map<String, dynamic> body =
'any': 'value',
'you': 'want for $error',
;
int statusCode = 404;
Uri destination = Uri.parse(url);
String json = jsonEncode(body);
return StreamedResponse(
Stream.value(json.codeUnits),
statusCode,
request: Request(httpMethod, destination),
);
-
使用Mahesh Jamdade答案中修改后的http multipart函数
Future<http.Response> makeAnyHttpRequest(String url,
Map<String, dynamic> body,
Function onTimeout,
Duration duration = const Duration(seconds: 10)) async
final request = http.MultipartRequest(
'POST',
Uri.parse('$url'),
);
final res = await request.send().timeout(
duration,
onTimeout: ()
return timeOutResponse(
httpMethod: 'MULTIPART POST',
error: 'Request Time Out',
url: url,
);
,
);
return await http.Response.fromStream(res);
这样,您可以返回onTimeOut
Http Response,而不是超时异常。
【讨论】:
【参考方案2】:你可以试试这个使用http package
用你想要的参数声明你的多部分函数
Future<http.Response> makeAnyHttpRequest(String url,
Map<String, dynamic> body,
Function onTimeout,
Duration duration = const Duration(seconds: 10)) async
final request = http.MultipartRequest(
'POST',
Uri.parse('$url'),
);
final res = await request.send().timeout(duration, onTimeout: onTimeout);
return await http.Response.fromStream(res);
然后在 try catch 块中调用它,您可以通过在 Timeout 上抛出所需的值来捕获超时异常。
try
final res = makeAnyHttpRequest("<url>","body":"here",onTimeout:()
throw 'TIME_OUT'; // Throw anything
);
catch(_)
if (_.toString() == 'TIME_OUT') // catch the thrown value to detect TIMEOUT
/// DO SOMETHING ON TIMEOUT
debugPrint('The request Timeout');
只要您有onTimeout
回调,上述方法适用于任何http 请求
【讨论】:
【参考方案3】:我建议
var request = http.MultipartRequest("POST", Uri.parse(EMPLOYEE_PUNCH_IN_URL));
request.fields['uid'] = userId;
request.fields['location'] = location;
request.fields['punchin_time'] = punchInTime;
request.fields['punchin_location_name'] = address;
var multiPartFile = await http.MultipartFile.fromPath(
"photo", imageFile.path,
contentType: MediaType("image", "$extension"));
request.files.add(multiPartFile);
await request.send().timeout(Duration(seconds: 1), onTimeout: ()
throw "TimeOut";
).then((onValue)
var responseByteArray = await onValue.stream.toBytes();
employeePunchInModel = standardSerializers.deserializeWith(
EmployeePunchInModel.serializer,
json.decode(utf8.decode(responseByteArray)));
).catchError(() throw "TimeOut";);
【讨论】:
会试一试 我收到一个错误firebasestorage.googleapis.com/v0/b/… @Nudge ..我编辑了 var responseByteArray = await onValue.stream.toBytes(); 不起作用。我试过你的解决方案。正如您在我在问题中提到的第二步中看到的那样,我使用的是您描述的相同解决方案。也许超时不适用于多部分 http。我想需要提交一个错误【参考方案4】:使用Dio 包和以下代码:
try
final response = await Dio().post(requestFinal.item1, data:formData, options: option,
onSendProgress: (sent, total)
print("uploadFile $sent / total");
);
print("Response Status code:: $response.statusCode");
if (response.statusCode >= 200 && response.statusCode < 299)
dynamic jsonResponse = response.data;
print("response body :: $jsonResponse");
final message = jsonResponse["msg"] ?? '';
final status = jsonResponse["status"] ?? 400;
final data = jsonResponse["data"];
return HttpResponse(status: status, errMessage: message, json: data);
else
dynamic jsonResponse = response.data;
print('*********************************************************');
print("response body :: $jsonResponse");
print('*********************************************************');
var errMessage = jsonResponse["msg"];
return HttpResponse(status: response.statusCode, errMessage: errMessage, json: jsonResponse);
on DioError catch(error)
print('*********************************************************');
print('Error Details :: $error.message');
print('*********************************************************');
dynamic jsonResponse = error.response.data;
print('*********************************************************');
print("response body :: $jsonResponse");
print('*********************************************************');
var errMessage = jsonResponse["message"] ?? "Something went wrong";
return HttpResponse(status: jsonResponse["status"] , errMessage: errMessage, json: null);
希望这会有所帮助!
【讨论】:
我知道 Diorites 库,但我不能使用它,因为我的办公室项目和我的团队领导不允许它使用【参考方案5】:你也可以使用 dio 3.0.4
一个强大的 Dart Http 客户端,支持拦截器、全局配置、FormData、请求取消、文件下载、超时等。
这是链接:Http client for Dart
【讨论】:
以上是关于如何在 Dart 中为 MultiPart 请求设置超时?的主要内容,如果未能解决你的问题,请参考以下文章
带有 multipart/form-data 的请求返回 415 错误
在 Android Studio 中为 Dart 启用彩虹括号