【问题标题】:How to set Timeout for MultiPart Request in Dart?如何在 Dart 中为 MultiPart 请求设置超时?
【发布时间】: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 框架

标签: http flutter dart


【解决方案1】:

使用http package,这是我的方法:

  1. 创建我们将用于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),
  );
}
  1. 使用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";});
      

      【讨论】:

      • 会试一试
      • @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

      【讨论】:

        猜你喜欢
        • 2022-12-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多