Flutter dio或http请求阻塞ui,导致页面UI卡顿问题及其解决办法

9,333 阅读2分钟

问题:在flutter开发中,关于dio请求数据的时候导致整个应用的ui卡顿。

在反复调试发现:ui卡顿的只有https协议下ios手机!

尝试剥析问题

首先,我的代码是这样的:

页面

provider文件

api请求

dio配置

一开始以为是dio的问题,后来用了flutter的原生库http还以一样卡顿,就猜想可能是自己代码的问题(老夫疲惫😫)!

解决方法一:开个线程玩玩

在pubspec.yaml中引入包:

在我们的main的文件中添入 // 顶层isolate负载均衡,初始化时开辟两个isolate

final Future<LoadBalancer> loadBalancer = LoadBalancer.create(2, IsolateRunner.spawn);

创建文件Resolve

/// resolve方法接收参数:{
/// url、token、method、params
/// }

import 'dart:convert';
import 'dart:isolate';

import 'package:dio/dio.dart';
import 'package:isolate/load_balancer.dart';
import 'package:xth2_mobile/main.dart';

Dio api = Dio();

/// 解析工作类
class Resolve {
  static Future<dynamic> resolve(Map data) async {
    final ReceivePort receivePort = ReceivePort();
    final LoadBalancer lb = await loadBalancer;
    // 开启一个线程
    await lb.run<dynamic, SendPort>(_parsingInIsolate, receivePort.sendPort);
    final SendPort sendPort = await receivePort.first;
    final ReceivePort resultPort = ReceivePort();
    // 把传进来的参数发送给_ParseMessageProtocol
    sendPort.send(_ParseMessageProtocol(data['token'], data['url'],
        data['method'] ?? 'get', data['params'] ?? {}, resultPort.sendPort));
    var res = await resultPort.first;
    return res;
  }
}

_parsingInIsolate(SendPort sendPort) {
  final ReceivePort receivePort = ReceivePort();
  sendPort.send(receivePort.sendPort);
  receivePort.listen((message) async {
    final String url = message.url;
    final String token = message.token;
    final String method = message.method;
    final Map params = message.params;
    try {
      final res = await http(url, token, method, params);
      Map sendData = parsedResult(res);
      message.sendPort.send(sendData);
    } catch (e) {
      print('resolve报错:$e');
      try {
        Map sendData = errorResult(e);
        message.sendPort.send(sendData);
      } catch (e) {
        print('resolve send error报错:$e');
      }
    }
  });
}

// 独立封装dio,对传进的参数进行请求
http(String url, String token, String method, Map params) async {
  api.options.contentType = 'application/json';
  api.options.connectTimeout = 30 * 1000;
  api.options.receiveTimeout = 30 * 1000;
  api.options.headers = {
    'x-access-token': token,
  };
  // 日志拦截器
  api.interceptors.add(LogInterceptor(responseBody: true));
  Response res;
  if (method == 'get') {
    res = await api.get(url);
  } else if (method == 'post') {
    if (params == {}) {
      res = await api.post(url);
    } else {
      res = await api.post(url, data: params);
    }
  } else if (method == 'put') {
    res = await api.put(url, data: params);
  } else if (method == 'head') {
    res = await api.head(url, data: params);
  } else if (method == 'delete') {
    res = await api.delete(url, data: params);
  }
  return res;
}

class _ParseMessageProtocol {
  final String token;
  final String url;
  final String method;
  final Map params;
  final SendPort sendPort;

  _ParseMessageProtocol(
      this.token, this.url, this.method, this.params, this.sendPort);
}

Map parsedResult(res) {
  dynamic result = json.decode(res.toString());
  Map sendData = {
    'code': result['code'],
    'msg': result['msg'],
    'data': result['data'],
  };
  return sendData;
}

Map errorResult(e) {
  Map sendData = {
    'code': 100000,
    'msg': e.toString(),
    'data': null,
  };
  return sendData;
}

然后我们就可以愉快的使用Isolate啦!😄

使用方法:

方法二: 终极解决方法

  • 换证书
1. 使用 ssl_stapling_file 配置,从一个外部文件获取ocsp信息 ngx_ssl_stapling_file
2. 使用 ssl_stapling_responder配置,nginx会用这个设置覆盖证书里面的Authority Information Access信息,使得请求ocsp被发送到设置的服务器

这里推荐第二种,如果在多台机器上部署的话第一种比较麻烦
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/ssl/ca-certs.pem;
ssl_stapling_responder http://YOUR_PROXY_IP:8080/; 
  • 如果是使用k8S + nginx-ingress 部署

首先将 nginx-ingress 更新到 0.31+ 这里有相关的变动日志。关于部署的冲突可以自行判断。

测试是否成功

openssl s_client -connect ${host}:443 -servername ${host} -status -tlsextdebug < /dev/null 2>&1 | grep -i "OCSP response"

将其中的 ${host} 改成自己的域名即可

OCSP response:
OCSP Response Data:
    OCSP Response Status: successful (0x0)
    Response Type: Basic OCSP Response

输出如上及说明已经解决了。

然后我们就可以继续愉快的玩耍Flutter啦!嘿嘿

生活不易,互相鼓励!!!

请看到这里的各位👍+关注!谢谢。

引用: