@@ -45,6 +45,30 @@ class DioUtils {
45
45
return status! < 400 ;
46
46
});
47
47
48
+ /// Get the location to which the [response] is redirected.
49
+ ///
50
+ /// If the response is not a valid redirect response, return null.
51
+ ///
52
+ /// It doesn't check whether the "location" is empty, relative, etc.
53
+ /// You should do it yourself.
54
+ ///
55
+ /// ## Formality
56
+ /// This method is a bit different from the original one (see [HttpClientResponse.isRedirect] in `http_impl.dart` ),
57
+ /// which considers the request HTTP method and excludes some invalid combinations (e.g., POST can only be redirected by 303).
58
+ /// But in practice, we don't need to (and cannot) be so strict. Some badly designed servers may return 302 for POST requests.
59
+ static String ? getRedirectLocation (Response <dynamic > response) {
60
+ final statusCode = response.statusCode;
61
+ bool isRedirect = statusCode == HttpStatus .movedPermanently ||
62
+ statusCode == HttpStatus .permanentRedirect ||
63
+ statusCode == HttpStatus .found ||
64
+ statusCode == HttpStatus .seeOther ||
65
+ statusCode == HttpStatus .temporaryRedirect;
66
+ if (isRedirect) {
67
+ return response.headers['location' ]? [0 ];
68
+ }
69
+ return null ;
70
+ }
71
+
48
72
/// Process the redirect response manually and return the final response.
49
73
///
50
74
/// What makes this method necessary is that the default behavior of [Dio] is
@@ -54,10 +78,8 @@ class DioUtils {
54
78
static Future <Response <dynamic >> processRedirect (
55
79
Dio dio, Response <dynamic > response) async {
56
80
// Prevent the redirect being processed by HttpClient, with the 302 response caught manually.
57
- if (response.statusCode == 302 &&
58
- response.headers['location' ] != null &&
59
- response.headers['location' ]! .isNotEmpty) {
60
- String location = response.headers['location' ]! [0 ];
81
+ String ? location = getRedirectLocation (response);
82
+ if (location != null ) {
61
83
if (location.isEmpty) return response;
62
84
if (! Uri .parse (location).isAbsolute) {
63
85
location = '${response .requestOptions .uri .origin }/$location ' ;
@@ -110,7 +132,9 @@ class DioUtils {
110
132
/// (The original [fetch] will throw a [DioException] WITHOUT the response data when [FormatException] occurs.)
111
133
static Future <Response <T >> fetchWithJsonError <T >(
112
134
Dio dio, RequestOptions options) async {
113
- if (T == dynamic || options.responseType == ResponseType .bytes || options.responseType == ResponseType .stream) {
135
+ if (T == dynamic ||
136
+ options.responseType == ResponseType .bytes ||
137
+ options.responseType == ResponseType .stream) {
114
138
// If T is dynamic, or the caller wants bytes or stream, just call the original fetch.
115
139
// Because we are going to parse the response data as [String] below!
116
140
return await dio.fetch (options) as Response <T >;
0 commit comments