Flutter网络请求进阶:请求加密、并发控制与异常监控实战
Flutter网络请求进阶:请求加密、并发控制与异常监控实战
在Flutter应用的网络交互场景中,除了离线缓存与弱网适配,“数据安全”“请求有序性”“问题可追溯性”同样是保障应用稳定性与用户信任的核心需求。未加密的请求易导致数据泄露,无控制的并发请求可能引发接口雪崩,缺乏监控的异常会让问题排查陷入困境。本文将聚焦这三大核心痛点,展开三大实战内容:请求全链路加密(请求头+请求体+响应体)、基于令牌桶的并发控制、异常分级监控与日志上报,帮助开发者构建“安全、可控、可追溯”的高级网络交互体系。
一、核心认知:进阶网络优化的设计原则
在动手实现前,需明确三大核心设计原则,避免陷入“加密冗余”“控制僵化”“监控泛滥”等坑:
-
安全分级原则:根据数据敏感度分级加密。核心数据(如用户密码、支付信息)采用非对称加密+对称加密组合方案;一般数据(如列表查询)采用对称加密即可,平衡安全性与性能。
-
并发适配原则:并发控制需适配业务场景。高频接口(如商品列表下拉刷新)采用宽松的并发限制,核心接口(如订单提交)采用严格的串行执行,避免一刀切的控制策略。
-
监控精准原则:异常监控需分级分类。区分“致命异常”(如网络中断、服务器宕机)、“警告异常”(如参数错误、超时)、“轻微异常”(如数据格式不规范),针对性上报与处理,避免日志冗余。
二、请求全链路加密:保障数据传输安全
本节将实现一套可扩展的请求加密方案,覆盖“请求头签名、请求体加密、响应体解密”全链路,基于AES对称加密(高效处理大量数据)与RSA非对称加密(安全传输对称密钥)的组合模式,兼顾安全性与性能。
1. 基础准备:加密工具类实现
封装AES与RSA加密工具,提供统一的加密、解密、签名、验签方法,屏蔽底层加密细节。
import 'dart:convert';
import 'dart:typed_data';
import 'package:crypto/crypto.dart';
import 'package:encrypt/encrypt.dart';
import 'package:pointycastle/asymmetric/rsa.dart';
import 'package:pointycastle/pointycastle.dart';
import 'package:pointycastle/paddings/pkcs7.dart';
import 'package:pointycastle/signers/rsa_signer.dart';
// 加密工具类(单例)
class EncryptUtil {
static final EncryptUtil _instance = EncryptUtil._internal();
factory EncryptUtil() => _instance;
EncryptUtil._internal();
// AES相关配置(密钥长度128/256位,IV长度16位)
static const int _aesKeyLength = 32; // 256位密钥
static const int _aesIVLength = 16;
// RSA相关配置(公钥用于加密AES密钥,私钥用于解密AES密钥)
late RSAAsymmetricKey _rsaPublicKey;
late RSAAsymmetricKey _rsaPrivateKey;
// 初始化RSA密钥对(实际项目中,公钥由服务端提供,私钥本地安全存储)
void initRSAKeyPair({required String publicKeyStr, required String privateKeyStr}) {
_rsaPublicKey = _parseRsaPublicKey(publicKeyStr);
_rsaPrivateKey = _parseRsaPrivateKey(privateKeyStr);
}
// 解析RSA公钥(PEM格式)
RSAAsymmetricKey _parseRsaPublicKey(String publicKeyStr) {
final publicKeyPem = publicKeyStr
.replaceAll('-----BEGIN PUBLIC KEY-----', '')
.replaceAll('-----END PUBLIC KEY-----', '')
.replaceAll('\n', '');
final publicKeyBytes = base64.decode(publicKeyPem);
final keyParams = RSAKeyParameters.fromPublicKeyBytes(publicKeyBytes, BigInt.from(65537));
return RSAPublicKey(keyParams.modulus!, keyParams.exponent!);
}
// 解析RSA私钥(PEM格式)
RSAAsymmetricKey _parseRsaPrivateKey(String privateKeyStr) {
final privateKeyPem = privateKeyStr
.replaceAll('-----BEGIN PRIVATE KEY-----', '')
.replaceAll('-----END PRIVATE KEY-----', '')
.replaceAll('\n', '');
final privateKeyBytes = base64.decode(privateKeyPem);
final keyParams = RSAKeyParameters.fromPrivateKeyBytes(privateKeyBytes);
return RSAPrivateKey(keyParams.modulus!, keyParams.exponent!, keyParams.p!, keyParams.q!);
}
// 生成随机AES密钥和IV
Map<String, String> generateAesKeyAndIV() {
final key = Uint8List(_aesKeyLength);
final iv = Uint8List(_aesIVLength);
// 生成随机字节(实际项目中需使用安全的随机数生成器)
final random = SecureRandom('AES/CTR/AUTO-SEED-PRNG');
random.seed(KeyParameter.fromSecureRandom(16));
random.nextBytes(key);
random.nextBytes(iv);
return {
'key': base64.encode(key),
'iv': base64.encode(iv),
};
}
// AES加密(CBC模式,PKCS7填充)
String aesEncrypt(String plainText, {required String keyStr, required String ivStr}) {
final key = Key.fromBase64(keyStr);
final iv = IV.fromBase64(ivStr);
final encrypter = Encrypter(AES(key, mode: AESMode.cbc, padding: 'PKCS7'));
final encrypted = encrypter.encrypt(plainText, iv: iv);
return encrypted.base64;
}
// AES解密(CBC模式,PKCS7填充)
String aesDecrypt(String cipherText, {required String keyStr, required String ivStr}) {
final key = Key.fromBase64(keyStr);
final iv = IV.fromBase64(ivStr);
final encrypter = Encrypter(AES(key, mode: AESMode.cbc, padding: 'PKCS7'));
final encrypted = Encrypted.fromBase64(cipherText);
return encrypter.decrypt(encrypted, iv: iv);
}
// RSA加密(用于加密AES密钥)
String rsaEncrypt(String plainText) {
final inputBytes = utf8.encode(plainText);
final engine = RSAEngine()
..init(true, PublicKeyParameter<RSAAsymmetricKey>(_rsaPublicKey));
final outputBytes = engine.process(inputBytes);
return base64.encode(outputBytes);
}
// RSA解密(用于解密AES密钥)
String rsaDecrypt(String cipherText) {
final inputBytes = base64.decode(cipherText);
final engine = RSAEngine()
..init(false, PrivateKeyParameter<RSAAsymmetricKey>(_rsaPrivateKey));
final outputBytes = engine.process(inputBytes);
return utf8.decode(outputBytes);
}
// 生成请求签名(MD5:timestamp+nonce+body+secret)
String generateSign({
required String timestamp,
required String nonce,
required String body,
required String secret,
}) {
final signStr = '$timestamp$nonce$body$secret';
final md5Bytes = md5.convert(utf8.encode(signStr)).bytes;
return base64.encode(md5Bytes);
}
// 验证响应签名
bool verifySign({
required String timestamp,
required String nonce,
required String body,
required String secret,
required String sign,
}) {
final generatedSign = generateSign(
timestamp: timestamp,
nonce: nonce,
body: body,
secret: secret,
);
return generatedSign == sign;
}
}
2. 实现加密拦截器:全链路自动加密解密
通过Dio拦截器实现请求的自动加密(请求头签名、请求体加密)与响应的自动解密(响应体解密、签名验证),无需在每个请求中手动处理加密逻辑。
import 'dart:math';
import 'package:dio/dio.dart';
import 'encrypt_util.dart';
// 加密拦截器配置
class EncryptInterceptorConfig {
// 是否开启加密(可动态开关,如调试环境关闭)
final bool enableEncrypt;
// 签名密钥(与服务端约定)
final String signSecret;
// 需要跳过加密的接口路径(如登录接口可能需要特殊处理)
final List<String> skipEncryptPaths;
EncryptInterceptorConfig({
this.enableEncrypt = true,
required this.signSecret,
this.skipEncryptPaths = const [],
});
}
// 加密拦截器(请求加密+响应解密)
class EncryptInterceptor extends Interceptor {
final EncryptInterceptorConfig config;
final EncryptUtil _encryptUtil = EncryptUtil();
EncryptInterceptor({required this.config});
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
// 1. 检查是否开启加密,或是否跳过当前接口
if (!config.enableEncrypt || config.skipEncryptPaths.contains(options.path)) {
handler.next(options);
return;
}
// 2. 生成请求公共参数(timestamp+nonce)
final timestamp = DateTime.now().millisecondsSinceEpoch.toString();
final nonce = _generateNonce(); // 随机字符串,防止重放攻击
// 3. 处理请求体:加密
final plainBody = options.data != null ? json.encode(options.data) : '';
final aesInfo = _encryptUtil.generateAesKeyAndIV();
final encryptedBody = _encryptUtil.aesEncrypt(
plainBody,
keyStr: aesInfo['key']!,
ivStr: aesInfo['iv']!,
);
// 4. 加密AES密钥(使用RSA公钥)
final encryptedAesKey = _encryptUtil.rsaEncrypt('${aesInfo['key']}:${aesInfo['iv']}');
// 5. 生成请求签名
final sign = _encryptUtil.generateSign(
timestamp: timestamp,
nonce: nonce,
body: plainBody,
secret: config.signSecret,
);
// 6. 构建加密后的请求参数
options.data = {
'encryptedBody': encryptedBody,
'encryptedAesKey': encryptedAesKey,
};
// 7. 设置请求头(签名+公共参数)
options.headers.addAll({
'timestamp': timestamp,
'nonce': nonce,
'sign': sign,
'encryptType': 'AES+RSA', // 告知服务端加密方式
});
handler.next(options);
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) async {
// 1. 检查是否开启加密,或是否跳过当前接口
if (!config.enableEncrypt || config.skipEncryptPaths.contains(response.requestOptions.path)) {
handler.next(response);
return;
}
// 2. 验证响应签名
final timestamp = response.headers.value('timestamp') ?? '';
final nonce = response.headers.value('nonce') ?? '';
final sign = response.headers.value('sign') ?? '';
final responseBody = json.encode(response.data);
final verifyResult = _encryptUtil.verifySign(
timestamp: timestamp,
nonce: nonce,
body: responseBody,
secret: config.signSecret,
sign: sign,
);
if (!verifyResult) {
handler.reject(
DioException(
requestOptions: response.requestOptions,
type: DioExceptionType.unknown,
error: '响应签名验证失败,可能存在数据篡改',
),
);
return;
}
// 3. 解密响应体
try {
// 从响应中获取加密的AES密钥和加密的响应体
final encryptedAesKey = response.data['encryptedAesKey'] as String;
final encryptedBody = response.data['encryptedBody'] as String;
// 解密AES密钥(使用RSA私钥)
final aesKeyAndIV = _encryptUtil.rsaDecrypt(encryptedAesKey);
final aesKey = aesKeyAndIV.split(':')[0];
final aesIV = aesKeyAndIV.split(':')[1];
// 解密响应体(AES)
final decryptedBody = _encryptUtil.aesDecrypt(
encryptedBody,
keyStr: aesKey,
ivStr: aesIV,
);
// 替换响应数据为解密后的数据
response.data = json.decode(decryptedBody);
handler.next(response);
} catch (e) {
handler.reject(
DioException(
requestOptions: response.requestOptions,
type: DioExceptionType.unknown,
error: '响应体解密失败:$e',
),
);
}
}
// 生成随机字符串(16位,用于nonce)
String _generateNonce() {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
final random = Random.secure();
return List.generate(16, (index) => chars[random.nextInt(chars.length)]).join();
}
}
三、并发控制:基于令牌桶算法的请求限流
高频次的并发请求(如下拉刷新+上拉加载同时触发、列表项批量请求)可能导致服务端压力过大、客户端资源占用过高,甚至引发接口雪崩。本节基于令牌桶算法实现请求限流,支持全局并发控制与接口级别的个性化配置。
1. 基础准备:令牌桶算法实现
令牌桶算法核心逻辑:系统以固定速率向桶中添加令牌,请求发起时需从桶中获取令牌,获取到令牌则继续执行,未获取到则等待或拒绝,实现平滑的流量控制。
import 'dart:async';
// 令牌桶(单例,支持动态调整速率和容量)
class TokenBucket {
static final TokenBucket _instance = TokenBucket._internal();
factory TokenBucket() => _instance;
TokenBucket._internal();
// 桶容量(最大令牌数)
int _capacity = 10;
// 令牌生成速率(令牌/秒)
double _rate = 5;
// 当前桶中令牌数
double _currentTokens = 0;
// 上次令牌生成时间(毫秒级时间戳)
int _lastRefillTime = DateTime.now().millisecondsSinceEpoch;
// 锁对象,保证并发安全
final Object _lock = Object();
// 初始化令牌桶
void init({required int capacity, required double rate}) {
_capacity = capacity;
_rate = rate;
_currentTokens = capacity.toDouble(); // 初始装满令牌
_lastRefillTime = DateTime.now().millisecondsSinceEpoch;
}
// 动态调整令牌生成速率
void adjustRate(double newRate) {
if (newRate > 0) {
_rate = newRate;
}
}
// 尝试获取令牌(返回是否获取成功)
bool tryAcquire({int tokens = 1}) {
if (tokens <= 0) return false;
synchronized(_lock, () {
// 1. 补充令牌(根据上次补充时间到现在的时长)
_refillTokens();
// 2. 检查是否有足够的令牌
if (_currentTokens >= tokens) {
_currentTokens -= tokens;
return true;
}
return false;
});
return false;
}
// 阻塞获取令牌(直到获取到为止)
Future<void> acquire({int tokens = 1}) async {
if (tokens <= 0) return;
while (true) {
if (tryAcquire(tokens: tokens)) {
return;
}
// 未获取到令牌,短暂等待后重试
await Future.delayed(const Duration(milliseconds: 50));
}
}
// 补充令牌
void _refillTokens() {
final now = DateTime.now().millisecondsSinceEpoch;
final elapsedTime = (now - _lastRefillTime) / 1000; // 秒数
if (elapsedTime <= 0) return;
// 生成新令牌数(速率 * 时间)
final newTokens = _rate * elapsedTime;
// 补充令牌,不超过桶容量
_currentTokens = min(_currentTokens + newTokens, _capacity.toDouble());
// 更新上次补充时间
_lastRefillTime = now;
}
// 清空令牌桶
void clear() {
synchronized(_lock, () {
_currentTokens = 0;
});
}
}
2. 实现并发控制拦截器:请求限流
通过Dio拦截器整合令牌桶算法,实现请求的自动限流。支持全局默认限流策略,也可在单个请求中配置个性化的限流参数(如是否跳过限流、所需令牌数)。
import 'package:dio/dio.dart';
import 'token_bucket.dart';
// 并发控制配置(单个请求的个性化配置)
class ConcurrentControlConfig {
// 是否跳过限流
final bool skipLimit;
// 获取令牌数(默认1个)
final int tokens;
ConcurrentControlConfig({
this.skipLimit = false,
this.tokens = 1,
});
}
// 并发控制拦截器(基于令牌桶的请求限流)
class ConcurrentControlInterceptor extends Interceptor {
final TokenBucket _tokenBucket = TokenBucket();
// 全局默认是否开启限流
final bool defaultEnableLimit;
ConcurrentControlInterceptor({
this.defaultEnableLimit = true,
}) {
// 初始化令牌桶(默认容量10,速率5令牌/秒,可根据业务调整)
_tokenBucket.init(capacity: 10, rate: 5);
}
@override
Future<void> onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
// 1. 获取当前请求的并发控制配置
final requestConfig = options.extra['concurrentControl'] as ConcurrentControlConfig? ??
ConcurrentControlConfig(skipLimit: !defaultEnableLimit);
// 2. 检查是否跳过限流
if (requestConfig.skipLimit) {
handler.next(options);
return;
}
// 3. 阻塞获取令牌(直到获取到为止)
await _tokenBucket.acquire(tokens: requestConfig.tokens);
handler.next(options);
}
// 动态调整令牌生成速率(如根据网络状态调整:弱网时降低速率)
void adjustTokenRate(double newRate) {
_tokenBucket.adjustRate(newRate);
}
}
四、异常监控:分级上报与日志记录
完善的异常监控体系能帮助开发者快速定位问题。本节实现“异常分级、日志记录、远程上报”三大功能,支持捕获网络请求全链路的异常(请求加密失败、请求超时、响应解密失败、服务端错误等),并按严重程度进行处理。
1. 基础准备:异常模型与分级枚举
定义网络异常模型,区分异常类型与严重级别,为后续的日志记录与上报提供基础。
import 'package:dio/dio.dart';
// 异常严重级别
enum ExceptionLevel {
fatal, // 致命异常(如网络中断、服务器宕机,影响核心功能)
warning, // 警告异常(如参数错误、超时,可恢复)
info, // 信息异常(如数据格式不规范,不影响功能)
}
// 网络异常模型
class NetworkException {
// 异常ID(唯一标识)
final String exceptionId;
// 异常级别
final ExceptionLevel level;
// 异常类型
final String type;
// 异常消息
final String message;
// 请求信息
final RequestInfo requestInfo;
// 异常发生时间(时间戳,毫秒级)
final int timestamp;
// 额外信息(如堆栈跟踪)
final Map<String, dynamic>? extra;
NetworkException({
required this.exceptionId,
required this.level,
required this.type,
required this.message,
required this.requestInfo,
required this.timestamp,
this.extra,
});
Map<String, dynamic> toJson() {
return {
'exceptionId': exceptionId,
'level': level.name,
'type': type,
'message': message,
'requestInfo': requestInfo.toJson(),
'timestamp': timestamp,
'extra': extra,
};
}
}
// 请求信息模型
class RequestInfo {
final String method;
final String path;
final String url;
final Map<String, dynamic>? queryParams;
final dynamic requestData;
final Map<String, dynamic>? headers;
final int? timeout;
RequestInfo({
required this.method,
required this.path,
required this.url,
this.queryParams,
this.requestData,
this.headers,
this.timeout,
});
Map<String, dynamic> toJson() {
return {
'method': method,
'path': path,
'url': url,
'queryParams': queryParams,
'requestData': requestData,
'headers': headers,
'timeout': timeout,
};
}
}
// 异常ID生成工具
String generateExceptionId() {
final timestamp = DateTime.now().millisecondsSinceEpoch.toString();
final random = DateTime.now().microsecond.toString().padLeft(6, '0');
return '$timestamp$random';
}
2. 实现异常监控拦截器:捕获与上报
通过Dio拦截器捕获请求全链路的异常,结合异常分级模型进行日志记录与远程上报。支持配置是否开启本地日志、是否开启远程上报,以及上报的异常级别阈值。
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'network_exception.dart';
// 异常监控配置
class ExceptionMonitorConfig {
// 是否开启本地日志记录
final bool enableLocalLog;
// 是否开启远程上报
final bool enableRemoteReport;
// 远程上报的级别阈值(只上报大于等于此级别的异常)
final ExceptionLevel reportLevelThreshold;
// 远程上报回调(由业务层实现具体的上报逻辑,如上传到服务器)
final Future<void> Function(NetworkException exception)? onReport;
ExceptionMonitorConfig({
this.enableLocalLog = true,
this.enableRemoteReport = true,
this.reportLevelThreshold = ExceptionLevel.warning,
this.onReport,
});
}
// 异常监控拦截器
class ExceptionMonitorInterceptor extends Interceptor {
final ExceptionMonitorConfig config;
ExceptionMonitorInterceptor({required this.config});
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
try {
handler.next(options);
} catch (e) {
// 捕获请求拦截器中的异常(如加密失败)
_handleException(
exception: e,
requestOptions: options,
level: ExceptionLevel.warning,
type: 'RequestInterceptorException',
);
handler.reject(DioException(requestOptions: options, error: e));
}
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
try {
// 检查响应数据是否规范(示例:要求响应必须是JSON格式)
if (response.data == null || !(response.data is Map) && !(response.data is List)) {
throw Exception('响应数据格式不规范,必须是JSON对象或数组');
}
handler.next(response);
} catch (e) {
// 捕获响应拦截器中的异常(如数据格式校验失败)
_handleException(
exception: e,
requestOptions: response.requestOptions,
level: ExceptionLevel.info,
type: 'ResponseDataException',
);
handler.next(response); // 数据格式不规范不中断流程,仅记录异常
}
}
@override
void onError(DioException err, ErrorInterceptorHandler handler) {
// 分类处理Dio异常
ExceptionLevel level;
String type;
String message;
switch (err.type) {
case DioExceptionType.connectionTimeout:
case DioExceptionType.sendTimeout:
case DioExceptionType.receiveTimeout:
level = ExceptionLevel.warning;
type = 'TimeoutException';
message = '请求超时';
break;
case DioExceptionType.connectionError:
level = ExceptionLevel.fatal;
type = 'ConnectionException';
message = '网络连接失败';
break;
case DioExceptionType.response:
level = ExceptionLevel.warning;
type = 'ResponseException';
message = '服务端错误,状态码:${err.response?.statusCode}';
break;
case DioExceptionType.cancel:
level = ExceptionLevel.info;
type = 'CancelException';
message = '请求被取消';
break;
default:
level = ExceptionLevel.warning;
type = 'UnknownException';
message = '未知异常';
break;
}
// 处理异常
_handleException(
exception: err.error ?? err,
requestOptions: err.requestOptions,
level: level,
type: type,
message: '$message:${err.message}',
);
handler.next(err);
}
// 统一处理异常:日志记录+远程上报
void _handleException({
required dynamic exception,
required RequestOptions requestOptions,
required ExceptionLevel level,
required String type,
String? message,
}) {
// 1. 构建异常模型
final requestInfo = RequestInfo(
method: requestOptions.method,
path: requestOptions.path,
url: requestOptions.uri.toString(),
queryParams: requestOptions.queryParameters,
requestData: requestOptions.data,
headers: requestOptions.headers,
timeout: requestOptions.connectTimeout?.inMilliseconds,
);
final networkException = NetworkException(
exceptionId: generateExceptionId(),
level: level,
type: type,
message: message ?? exception.toString(),
requestInfo: requestInfo,
timestamp: DateTime.now().millisecondsSinceEpoch,
extra: {
'stackTrace': exception is Error ? exception.stackTrace.toString() : '',
},
);
// 2. 本地日志记录
if (config.enableLocalLog) {
_logException(networkException);
}
// 3. 远程上报(仅上报级别大于等于阈值的异常)
if (config.enableRemoteReport && _shouldReport(level)) {
_reportException(networkException);
}
}
// 本地日志记录(调试环境打印,生产环境可写入本地文件)
void _logException(NetworkException exception) {
if (kDebugMode) {
print('\n===== 网络异常日志 =====');
print('异常ID:${exception.exceptionId}');
print('级别:${exception.level.name}');
print('类型:${exception.type}');
print('消息:${exception.message}');
print('请求信息:${json.encode(exception.requestInfo.toJson(), indent: 2)}');
print('额外信息:${json.encode(exception.extra, indent: 2)}');
print('======================\n');
}
// 生产环境可在此处将日志写入本地文件,便于后续排查
}
// 远程上报异常
Future<void> _reportException(NetworkException exception) async {
if (config.onReport != null) {
try {
await config.onReport!(exception);
} catch (e) {
if (kDebugMode) {
print('异常上报失败:$e');
}
}
}
}
// 判断是否需要上报(级别大于等于阈值)
bool _shouldReport(ExceptionLevel level) {
return level.index >= config.reportLevelThreshold.index;
}
}
3. 在NetworkUtil中整合所有进阶功能
将加密拦截器、并发控制拦截器、异常监控拦截器整合到NetworkUtil中,形成完整的高级网络请求体系,并提供统一的请求封装方法。
import 'package:dio/dio.dart';
import 'encrypt_interceptor.dart';
import 'concurrent_control_interceptor.dart';
import 'exception_monitor_interceptor.dart';
import 'encrypt_util.dart';
class AdvancedNetworkUtil {
static final AdvancedNetworkUtil _instance = AdvancedNetworkUtil._internal();
factory AdvancedNetworkUtil() => _instance;
late Dio _dio;
late EncryptUtil _encryptUtil;
late ConcurrentControlInterceptor _concurrentInterceptor;
AdvancedNetworkUtil._internal() {
_encryptUtil = EncryptUtil();
_initDio();
}
// 初始化Dio(整合所有拦截器)
void _initDio() {
_dio = Dio();
// 1. 初始化加密工具(实际项目中,公钥从服务端获取,私钥本地安全存储)
_encryptUtil.initRSAKeyPair(
publicKeyStr: '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----',
privateKeyStr: '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----',
);
// 2. 添加异常监控拦截器(最先添加,捕获所有环节的异常)
_dio.interceptors.add(
ExceptionMonitorInterceptor(
config: ExceptionMonitorConfig(
enableLocalLog: true,
enableRemoteReport: true,
reportLevelThreshold: ExceptionLevel.warning,
onReport: (exception) async {
// 实现远程上报逻辑(如POST到服务端的异常监控接口)
await _dio.post(
'monitor/network/exception',
data: exception.toJson(),
options: Options(extra: {'concurrentControl': ConcurrentControlConfig(skipLimit: true)}),
);
},
),
),
);
// 3. 添加并发控制拦截器
_concurrentInterceptor = ConcurrentControlInterceptor(defaultEnableLimit: true);
_dio.interceptors.add(_concurrentInterceptor);
// 4. 添加加密拦截器
_dio.interceptors.add(
EncryptInterceptor(
config: EncryptInterceptorConfig(
enableEncrypt: true,
signSecret: 'your_sign_secret', // 与服务端约定的签名密钥
skipEncryptPaths: ['/api/login'], // 登录接口跳过加密
),
),
);
// 5. 其他基础配置(如基础URL、超时时间默认值)
_dio.options.baseUrl = 'https://api.your-domain.com';
_dio.options.connectTimeout = const Duration(milliseconds: 15000);
}
// 动态调整并发控制速率(如弱网时降低速率)
void adjustConcurrentRate(double newRate) {
_concurrentInterceptor.adjustTokenRate(newRate);
}
// 动态开关加密功能
void toggleEncrypt(bool enable) {
final encryptInterceptor = _dio.interceptors.firstWhere(
(interceptor) => interceptor is EncryptInterceptor,
) as EncryptInterceptor;
encryptInterceptor.config = encryptInterceptor.config.copyWith(enableEncrypt: enable);
}
// 封装带进阶功能的请求方法
Future<T?> request<T>(
String path, {
required String method,
Map<String, dynamic>? queryParams,
dynamic data,
Options? options,
// 并发控制配置
ConcurrentControlConfig? concurrentControl,
// 加密配置(是否跳过当前请求的加密)
bool skipEncrypt = false,
}) async {
final extra = <String, dynamic>{};
if (concurrentControl != null) {
extra['concurrentControl'] = concurrentControl;
}
if (skipEncrypt) {
extra['skipEncrypt'] = true;
}
final requestOptions = Options(
method: method,
...options,
extra: {
...options?.extra ?? {},
...extra,
},
);
try {
final response = await _dio.request(
path,
queryParameters: queryParams,
data: data,
options: requestOptions,
);
return response.data as T?;
} catch (e) {
if (kDebugMode) {
print('请求失败:$e');
}
rethrow;
}
}
// 封装GET请求
Future<T?> get<T>(
String path, {
Map<String, dynamic>? queryParams,
Options? options,
ConcurrentControlConfig? concurrentControl,
bool skipEncrypt = false,
}) =>
request<T>(
path,
method: 'GET',
queryParams: queryParams,
options: options,
concurrentControl: concurrentControl,
skipEncrypt: skipEncrypt,
);
// 封装POST请求
Future<T?> post<T>(
String path, {
dynamic data,
Map<String, dynamic>? queryParams,
Options? options,
ConcurrentControlConfig? concurrentControl,
bool skipEncrypt = false,
}) =>
request<T>(
path,
method: 'POST',
data: data,
queryParams: queryParams,
options: options,
concurrentControl: concurrentControl,
skipEncrypt: skipEncrypt,
);
}
final advancedNetUtil = AdvancedNetworkUtil();
五、结语:构建“安全、可控、可追溯”的高级网络体系
Flutter应用的网络请求进阶优化,核心是“安全防护+流量控制+问题追溯”的三位一体。本文从请求全链路加密、基于令牌桶的并发控制,到分级异常监控与上报,形成了覆盖“数据安全-流量可控-问题可追溯”的全链路实战方案,与上一篇的“离线缓存-弱网适配”形成互补,共同构建企业级的稳定网络交互体系。
欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。
更多推荐




所有评论(0)