import 'package:dio/dio.dart'; /// Creates Dio instances that automatically follow redirects for all HTTP /// methods (including POST). The default Dio/dart:io behaviour only follows /// redirects for GET, so POST→301/302 would otherwise throw. Dio createDio([BaseOptions? options]) { final dio = Dio(options); dio.interceptors.add(_RedirectInterceptor()); return dio; } /// Interceptor that follows 3xx redirects for any HTTP method. class _RedirectInterceptor extends Interceptor { static const _maxRedirects = 5; @override void onResponse(Response response, ResponseInterceptorHandler handler) { handler.next(response); } @override void onError(DioException err, ErrorInterceptorHandler handler) async { final statusCode = err.response?.statusCode; if (statusCode == null || statusCode < 300 || statusCode > 399 || statusCode == 304) { return handler.next(err); } final location = err.response?.headers.value('location'); if (location == null) { return handler.next(err); } final originalUri = err.requestOptions.uri; final redirectUri = Uri.parse(location).isAbsolute ? Uri.parse(location) : originalUri.resolve(location); // Preserve method for 307/308, change to GET for 301/302/303 final preserveMethod = statusCode == 307 || statusCode == 308; final method = preserveMethod ? err.requestOptions.method : 'GET'; final dio = Dio(); dio.interceptors.add(this); // follow further redirects var redirects = 0; var opts = Options( method: method, headers: Map.of(err.requestOptions.headers), responseType: err.requestOptions.responseType, validateStatus: err.requestOptions.validateStatus, followRedirects: false, // we handle it ourselves ); var currentUri = redirectUri; Response? response; while (redirects < _maxRedirects) { redirects++; try { response = await dio.requestUri( currentUri, data: preserveMethod ? err.requestOptions.data : null, options: opts, ); break; } on DioException catch (e) { final sc = e.response?.statusCode; final loc = e.response?.headers.value('location'); if (sc != null && sc >= 300 && sc <= 399 && sc != 304 && loc != null) { currentUri = Uri.parse(loc).isAbsolute ? Uri.parse(loc) : currentUri.resolve(loc); if (sc == 301 || sc == 302 || sc == 303) { opts = opts.copyWith(method: 'GET'); } continue; } return handler.next(e); } } if (response != null) { return handler.resolve(response); } return handler.next(err); } }