Files
PiliPlus/lib/http/retry_interceptor.dart
HeXis-YS 7f2682bb7b opt(download): force cache downloads to use http/1.1 (#1870)
* opt(download): force cache downloads to use http/1.1

* refactor(http): lazily initialize fallback http/1.1 client

* fix(http): keep fallback client decision consistent at startup

* opt: use clone

* fix

* fix

---------

Co-authored-by: My-Responsitories <107370289+My-Responsitories@users.noreply.github.com>
2026-03-17 12:43:03 +00:00

83 lines
2.7 KiB
Dart

import 'package:dio/dio.dart';
import 'package:http2/http2.dart';
class RetryInterceptor extends Interceptor {
final Dio _client;
final int _count;
final int _delay;
RetryInterceptor(this._client, this._count, this._delay);
@override
void onError(DioException err, ErrorInterceptorHandler handler) {
if (err.requestOptions.responseType == ResponseType.stream) {
return handler.next(err);
}
if (err.response != null) {
final options = err.requestOptions;
if (options.followRedirects && options.maxRedirects > 0) {
final status = err.response!.statusCode;
if (status != null && 300 <= status && status < 400) {
var redirectUrl = err.response!.headers.value('location');
if (redirectUrl != null) {
var uri = Uri.parse(redirectUrl);
if (!uri.hasScheme) {
uri = options.uri.resolveUri(uri);
redirectUrl = uri.toString();
}
(options..path = redirectUrl).maxRedirects--;
if (status == 303) {
options
..data = null
..method = 'GET';
}
_client
.fetch(options)
.then(
(i) => handler.resolve(
i
..redirects.add(
RedirectRecord(status, options.method, uri),
)
..isRedirect = true,
),
)
.onError<DioException>((error, _) => handler.next(error));
return;
}
}
}
return handler.next(err);
} else {
switch (err.type) {
case DioExceptionType.connectionError:
case DioExceptionType.connectionTimeout:
case DioExceptionType.sendTimeout:
case DioExceptionType.unknown:
if ((err.requestOptions.extra['_rt'] ??= 0) < _count &&
err.error
is! TransportConnectionException // 网络中断, 此时请求可能已经被服务器所接收
) {
Future.delayed(
Duration(
milliseconds: ++err.requestOptions.extra['_rt'] * _delay,
),
() => _client
.fetch(err.requestOptions)
.then(handler.resolve)
.onError<DioException>((error, _) => handler.reject(error)),
);
} else {
handler.next(err);
}
return;
default:
return handler.next(err);
}
}
}
RetryInterceptor copyWith({Dio? client, int? count, int? delay}) =>
.new(client ?? _client, count ?? _count, delay ?? _delay);
}