Line data Source code
1 : import 'adapter.dart';
2 : import 'headers.dart';
3 : import 'transformer.dart';
4 : import 'cancel_token.dart';
5 :
6 : /// Callback to listen the progress for sending/receiving data.
7 : ///
8 : /// [count] is the length of the bytes have been sent/received.
9 : ///
10 : /// [total] is the content length of the response/request body.
11 : /// 1.When receiving data:
12 : /// [total] is the request body length.
13 : /// 2.When receiving data:
14 : /// [total] will be -1 if the size of the response body is not known in advance,
15 : /// for example: response data is compressed with gzip or no content-length header.
16 : typedef ProgressCallback = void Function(int count, int total);
17 :
18 : /// ResponseType indicates which transformation should
19 : /// be automatically applied to the response data by Dio.
20 7 : enum ResponseType {
21 : /// Transform the response data to JSON object only when the
22 : /// content-type of response is "application/json" .
23 6 : json,
24 :
25 : /// Get the response stream without any transformation. The
26 : /// Response data will be a `ResponseBody` instance.
27 : ///
28 : /// Response<ResponseBody> rs = await Dio().get<ResponseBody>(
29 : /// url,
30 : /// options: Options(
31 : /// responseType: ResponseType.stream,
32 : /// ),
33 : /// );
34 6 : stream,
35 :
36 : /// Transform the response data to a String encoded with UTF8.
37 6 : plain,
38 :
39 : /// Get original bytes, the type of [Response.data] will be List<int>
40 6 : bytes
41 : }
42 :
43 : typedef ValidateStatus = bool Function(int status);
44 : typedef ResponseDecoder = String Function(
45 : List<int> responseBytes, RequestOptions options, ResponseBody responseBody);
46 : typedef RequestEncoder = List<int> Function(
47 : String request, RequestOptions options);
48 :
49 : /// The common config for the Dio instance.
50 : /// `dio.options` is a instance of [BaseOptions]
51 : class BaseOptions extends _RequestConfig {
52 5 : BaseOptions({
53 : String method,
54 : this.connectTimeout,
55 : int receiveTimeout,
56 : int sendTimeout,
57 : this.baseUrl,
58 : this.queryParameters,
59 : Map<String, dynamic> extra,
60 : Map<String, dynamic> headers,
61 : ResponseType responseType = ResponseType.json,
62 : String contentType,
63 : ValidateStatus validateStatus,
64 : bool receiveDataWhenStatusError = true,
65 : bool followRedirects = true,
66 : int maxRedirects = 5,
67 : RequestEncoder requestEncoder,
68 : ResponseDecoder responseDecoder,
69 5 : }) : super(
70 : method: method,
71 : receiveTimeout: receiveTimeout,
72 : sendTimeout: sendTimeout,
73 : extra: extra,
74 : headers: headers,
75 : responseType: responseType,
76 : contentType: contentType,
77 : validateStatus: validateStatus,
78 : receiveDataWhenStatusError: receiveDataWhenStatusError,
79 : followRedirects: followRedirects,
80 : maxRedirects: maxRedirects,
81 : requestEncoder: requestEncoder,
82 : responseDecoder: responseDecoder,
83 : );
84 :
85 : /// Create a Option from current instance with merging attributes.
86 1 : BaseOptions merge({
87 : String method,
88 : String baseUrl,
89 : Map<String, dynamic> queryParameters,
90 : String path,
91 : int connectTimeout,
92 : int receiveTimeout,
93 : int sendTimeout,
94 : Map<String, dynamic> extra,
95 : Map<String, dynamic> headers,
96 : ResponseType responseType,
97 : String contentType,
98 : ValidateStatus validateStatus,
99 : bool receiveDataWhenStatusError,
100 : bool followRedirects,
101 : int maxRedirects,
102 : RequestEncoder requestEncoder,
103 : ResponseDecoder responseDecoder,
104 : }) {
105 1 : return BaseOptions(
106 0 : method: method ?? this.method,
107 0 : baseUrl: baseUrl ?? this.baseUrl,
108 1 : queryParameters: queryParameters ?? this.queryParameters,
109 1 : connectTimeout: connectTimeout ?? this.connectTimeout,
110 0 : receiveTimeout: receiveTimeout ?? this.receiveTimeout,
111 0 : sendTimeout: sendTimeout ?? this.sendTimeout,
112 0 : extra: extra ?? Map.from(this.extra ?? {}),
113 0 : headers: headers ?? Map.from(this.headers ?? {}),
114 1 : responseType: responseType ?? this.responseType,
115 0 : contentType: contentType ?? this.contentType,
116 1 : validateStatus: validateStatus ?? this.validateStatus,
117 : receiveDataWhenStatusError:
118 1 : receiveDataWhenStatusError ?? this.receiveDataWhenStatusError,
119 1 : followRedirects: followRedirects ?? this.followRedirects,
120 1 : maxRedirects: maxRedirects ?? this.maxRedirects,
121 : requestEncoder: requestEncoder,
122 1 : responseDecoder: responseDecoder ?? this.responseDecoder,
123 : );
124 : }
125 :
126 : /// Request base url, it can contain sub path, like: "https://www.google.com/api/".
127 : String baseUrl;
128 :
129 : /// Common query parameters
130 : Map<String, dynamic> queryParameters;
131 :
132 : /// Timeout in milliseconds for opening url.
133 : /// [Dio] will throw the [DioError] with [DioErrorType.CONNECT_TIMEOUT] type
134 : /// when time out.
135 : int connectTimeout;
136 : }
137 :
138 : /// Every request can pass an [Options] object which will be merged with [Dio.options]
139 : class Options extends _RequestConfig {
140 5 : Options({
141 : String method,
142 : int sendTimeout,
143 : int receiveTimeout,
144 : Map<String, dynamic> extra,
145 : Map<String, dynamic> headers,
146 : ResponseType responseType,
147 : String contentType,
148 : ValidateStatus validateStatus,
149 : bool receiveDataWhenStatusError,
150 : bool followRedirects,
151 : int maxRedirects,
152 : RequestEncoder requestEncoder,
153 : ResponseDecoder responseDecoder,
154 5 : }) : super(
155 : method: method,
156 : sendTimeout: sendTimeout,
157 : receiveTimeout: receiveTimeout,
158 : extra: extra,
159 : headers: headers,
160 : responseType: responseType,
161 : contentType: contentType,
162 : validateStatus: validateStatus,
163 : receiveDataWhenStatusError: receiveDataWhenStatusError,
164 : followRedirects: followRedirects,
165 : maxRedirects: maxRedirects,
166 : requestEncoder: requestEncoder,
167 : responseDecoder: responseDecoder,
168 : );
169 :
170 : /// Create a Option from current instance with merging attributes.
171 1 : Options merge({
172 : String method,
173 : int sendTimeout,
174 : int receiveTimeout,
175 : Map<String, dynamic> extra,
176 : Map<String, dynamic> headers,
177 : ResponseType responseType,
178 : String contentType,
179 : ValidateStatus validateStatus,
180 : bool receiveDataWhenStatusError,
181 : bool followRedirects,
182 : int maxRedirects,
183 : RequestEncoder requestEncoder,
184 : ResponseDecoder responseDecoder,
185 : }) {
186 1 : return Options(
187 0 : method: method ?? this.method,
188 0 : sendTimeout: sendTimeout ?? this.sendTimeout,
189 0 : receiveTimeout: receiveTimeout ?? this.receiveTimeout,
190 0 : extra: extra ?? Map.from(this.extra ?? {}),
191 0 : headers: headers ?? Map.from(this.headers ?? {}),
192 1 : responseType: responseType ?? this.responseType,
193 0 : contentType: contentType ?? this.contentType,
194 1 : validateStatus: validateStatus ?? this.validateStatus,
195 : receiveDataWhenStatusError:
196 1 : receiveDataWhenStatusError ?? this.receiveDataWhenStatusError,
197 1 : followRedirects: followRedirects ?? this.followRedirects,
198 1 : maxRedirects: maxRedirects ?? this.maxRedirects,
199 : requestEncoder: requestEncoder,
200 1 : responseDecoder: responseDecoder ?? this.responseDecoder,
201 : );
202 : }
203 : }
204 :
205 : class RequestOptions extends Options {
206 5 : RequestOptions({
207 : String method,
208 : int sendTimeout,
209 : int receiveTimeout,
210 : this.connectTimeout,
211 : this.data,
212 : this.path,
213 : this.queryParameters,
214 : this.baseUrl,
215 : this.onReceiveProgress,
216 : this.onSendProgress,
217 : this.cancelToken,
218 : Map<String, dynamic> extra,
219 : Map<String, dynamic> headers,
220 : ResponseType responseType,
221 : String contentType,
222 : ValidateStatus validateStatus,
223 : bool receiveDataWhenStatusError,
224 : bool followRedirects,
225 : int maxRedirects,
226 : RequestEncoder requestEncoder,
227 : ResponseDecoder responseDecoder,
228 5 : }) : super(
229 : method: method,
230 : sendTimeout: sendTimeout,
231 : receiveTimeout: receiveTimeout,
232 : extra: extra,
233 : headers: headers,
234 : responseType: responseType,
235 : contentType: contentType,
236 : validateStatus: validateStatus,
237 : receiveDataWhenStatusError: receiveDataWhenStatusError,
238 : followRedirects: followRedirects,
239 : maxRedirects: maxRedirects,
240 : requestEncoder: requestEncoder,
241 : responseDecoder: responseDecoder,
242 : );
243 :
244 : /// Create a Option from current instance with merging attributes.
245 1 : @override
246 : RequestOptions merge({
247 : String method,
248 : int sendTimeout,
249 : int receiveTimeout,
250 : int connectTimeout,
251 : String data,
252 : String path,
253 : Map<String, dynamic> queryParameters,
254 : String baseUrl,
255 : ProgressCallback onReceiveProgress,
256 : ProgressCallback onSendProgress,
257 : CancelToken cancelToken,
258 : Map<String, dynamic> extra,
259 : Map<String, dynamic> headers,
260 : ResponseType responseType,
261 : String contentType,
262 : ValidateStatus validateStatus,
263 : bool receiveDataWhenStatusError,
264 : bool followRedirects,
265 : int maxRedirects,
266 : RequestEncoder requestEncoder,
267 : ResponseDecoder responseDecoder,
268 : }) {
269 1 : return RequestOptions(
270 0 : method: method ?? this.method,
271 0 : sendTimeout: sendTimeout ?? this.sendTimeout,
272 0 : receiveTimeout: receiveTimeout ?? this.receiveTimeout,
273 1 : connectTimeout: connectTimeout ?? this.connectTimeout,
274 0 : data: data ?? this.data,
275 0 : path: path ?? this.path,
276 1 : queryParameters: queryParameters ?? this.queryParameters,
277 1 : baseUrl: baseUrl ?? this.baseUrl,
278 1 : onReceiveProgress: onReceiveProgress ?? this.onReceiveProgress,
279 1 : onSendProgress: onSendProgress ?? this.onSendProgress,
280 1 : cancelToken: cancelToken ?? this.cancelToken,
281 0 : extra: extra ?? Map.from(this.extra ?? {}),
282 0 : headers: headers ?? Map.from(this.headers ?? {}),
283 1 : responseType: responseType ?? this.responseType,
284 0 : contentType: contentType ?? this.contentType,
285 1 : validateStatus: validateStatus ?? this.validateStatus,
286 : receiveDataWhenStatusError:
287 1 : receiveDataWhenStatusError ?? this.receiveDataWhenStatusError,
288 1 : followRedirects: followRedirects ?? this.followRedirects,
289 1 : maxRedirects: maxRedirects ?? this.maxRedirects,
290 : requestEncoder: requestEncoder,
291 1 : responseDecoder: responseDecoder ?? this.responseDecoder,
292 : );
293 : }
294 :
295 : /// generate uri
296 5 : Uri get uri {
297 5 : var _url = path;
298 10 : if (!_url.startsWith(RegExp(r'https?:'))) {
299 6 : _url = baseUrl + _url;
300 3 : var s = _url.split(':/');
301 15 : _url = s[0] + ':/' + s[1].replaceAll('//', '/');
302 : }
303 10 : var query = Transformer.urlEncodeMap(queryParameters);
304 5 : if (query.isNotEmpty) {
305 3 : _url += (_url.contains('?') ? '&' : '?') + query;
306 : }
307 : // Normalize the url.
308 10 : return Uri.parse(_url).normalizePath();
309 : }
310 :
311 : /// Request data, can be any type.
312 : dynamic data;
313 :
314 : /// Request base url, it can contain sub path, like: 'https://www.google.com/api/'.
315 : String baseUrl;
316 :
317 : /// If the `path` starts with 'http(s)', the `baseURL` will be ignored, otherwise,
318 : /// it will be combined and then resolved with the baseUrl.
319 : String path = '';
320 :
321 : /// See [Uri.queryParameters]
322 : Map<String, dynamic> queryParameters;
323 :
324 : CancelToken cancelToken;
325 :
326 : ProgressCallback onReceiveProgress;
327 :
328 : ProgressCallback onSendProgress;
329 :
330 : int connectTimeout;
331 : }
332 :
333 : /// The [_RequestConfig] class describes the http request information and configuration.
334 : class _RequestConfig {
335 5 : _RequestConfig({
336 : this.method,
337 : this.receiveTimeout,
338 : this.sendTimeout,
339 : Map<String, dynamic> extra,
340 : Map<String, dynamic> headers,
341 : String contentType,
342 : this.responseType,
343 : this.validateStatus,
344 : this.receiveDataWhenStatusError = true,
345 : this.followRedirects = true,
346 : this.maxRedirects = 5,
347 : this.requestEncoder,
348 : this.responseDecoder,
349 : }) {
350 10 : this.headers = headers ?? {};
351 10 : this.extra = extra ?? {};
352 5 : this.contentType = contentType;
353 5 : this.headers =
354 30 : this.headers.map((key, v) => MapEntry(key.toLowerCase().toString(), v));
355 : }
356 :
357 : /// Http method.
358 : String method;
359 :
360 : /// Http request headers. The keys of initial headers will be converted to lowercase,
361 : /// for example 'Content-Type' will be converted to 'content-type'.
362 : ///
363 : /// You should use lowercase as the key name when you need to set the request header.
364 : Map<String, dynamic> headers;
365 :
366 : /// Timeout in milliseconds for sending data.
367 : /// [Dio] will throw the [DioError] with [DioErrorType.SEND_TIMEOUT] type
368 : /// when time out.
369 : int sendTimeout;
370 :
371 : /// Timeout in milliseconds for receiving data.
372 : /// [Dio] will throw the [DioError] with [DioErrorType.RECEIVE_TIMEOUT] type
373 : /// when time out.
374 : ///
375 : /// [0] meanings no timeout limit.
376 : int receiveTimeout;
377 :
378 : /// The request Content-Type. The default value is [ContentType.json].
379 : /// If you want to encode request body with 'application/x-www-form-urlencoded',
380 : /// you can set `ContentType.parse('application/x-www-form-urlencoded')`, and [Dio]
381 : /// will automatically encode the request body.
382 5 : set contentType(String contentType) {
383 20 : headers[Headers.contentTypeHeader] = contentType?.toLowerCase()?.trim();
384 : }
385 :
386 15 : String get contentType => headers[Headers.contentTypeHeader];
387 :
388 : /// [responseType] indicates the type of data that the server will respond with
389 : /// options which defined in [ResponseType] are `json`, `stream`, `plain`.
390 : ///
391 : /// The default value is `json`, dio will parse response string to json object automatically
392 : /// when the content-type of response is 'application/json'.
393 : ///
394 : /// If you want to receive response data with binary bytes, for example,
395 : /// downloading a image, use `stream`.
396 : ///
397 : /// If you want to receive the response data with String, use `plain`.
398 : ///
399 : /// If you want to receive the response data with original bytes,
400 : /// that's to say the type of [Response.data] will be List<int>, use `bytes`
401 : ResponseType responseType;
402 :
403 : /// `validateStatus` defines whether the request is successful for a given
404 : /// HTTP response status code. If `validateStatus` returns `true` ,
405 : /// the request will be perceived as successful; otherwise, considered as failed.
406 : ValidateStatus validateStatus;
407 :
408 : /// Whether receiving response data when http status code is not successful.
409 : bool receiveDataWhenStatusError;
410 :
411 : /// Custom field that you can retrieve it later in [Interceptor]、[Transformer] and the [Response] object.
412 : Map<String, dynamic> extra;
413 :
414 : /// see [HttpClientRequest.followRedirects]
415 : bool followRedirects;
416 :
417 : /// Set this property to the maximum number of redirects to follow
418 : /// when [followRedirects] is `true`. If this number is exceeded
419 : /// an error event will be added with a [RedirectException].
420 : ///
421 : /// The default value is 5.
422 : int maxRedirects;
423 :
424 : /// The default request encoder is utf8encoder, you can set custom
425 : /// encoder by this option.
426 : RequestEncoder requestEncoder;
427 :
428 : /// The default response decoder is utf8decoder, you can set custom
429 : /// decoder by this option, it will be used in [Transformer].
430 : ResponseDecoder responseDecoder;
431 : }
|