Line data Source code
1 : import 'adapter.dart';
2 : import 'cancel_token.dart';
3 : import 'headers.dart';
4 : import 'transformer.dart';
5 : import 'utils.dart';
6 :
7 : /// Callback to listen the progress for sending/receiving data.
8 : ///
9 : /// [count] is the length of the bytes have been sent/received.
10 : ///
11 : /// [total] is the content length of the response/request body.
12 : /// 1.When receiving data:
13 : /// [total] is the request body length.
14 : /// 2.When receiving data:
15 : /// [total] will be -1 if the size of the response body is not known in advance,
16 : /// for example: response data is compressed with gzip or no content-length header.
17 : typedef ProgressCallback = void Function(int count, int total);
18 :
19 : /// ResponseType indicates which transformation should
20 : /// be automatically applied to the response data by Dio.
21 12 : enum ResponseType {
22 : /// Transform the response data to JSON object only when the
23 : /// content-type of response is "application/json" .
24 : json,
25 :
26 : /// Get the response stream without any transformation. The
27 : /// Response data will be a `ResponseBody` instance.
28 : ///
29 : /// Response<ResponseBody> rs = await Dio().get<ResponseBody>(
30 : /// url,
31 : /// options: Options(
32 : /// responseType: ResponseType.stream,
33 : /// ),
34 : /// );
35 : stream,
36 :
37 : /// Transform the response data to a String encoded with UTF8.
38 : plain,
39 :
40 : /// Get original bytes, the type of [Response.data] will be List<int>
41 : bytes
42 : }
43 :
44 : /// ListFormat specifies the array format
45 : /// (a single parameter with multiple parameter or multiple parameters with the same name)
46 : /// and the separator for array items.
47 11 : enum ListFormat {
48 : /// Comma-separated values
49 : /// e.g. (foo,bar,baz)
50 : csv,
51 :
52 : /// Space-separated values
53 : /// e.g. (foo bar baz)
54 : ssv,
55 :
56 : /// Tab-separated values
57 : /// e.g. (foo\tbar\tbaz)
58 : tsv,
59 :
60 : /// Pipe-separated values
61 : /// e.g. (foo|bar|baz)
62 : pipes,
63 :
64 : /// Multiple parameter instances rather than multiple values.
65 : /// e.g. (foo=value&foo=another_value)
66 : multi,
67 :
68 : /// Forward compatibility
69 : /// e.g. (foo[]=value&foo[]=another_value)
70 : multiCompatible,
71 : }
72 :
73 : typedef ValidateStatus = bool Function(int? status);
74 :
75 : typedef ResponseDecoder = String Function(
76 : List<int> responseBytes, RequestOptions options, ResponseBody responseBody);
77 : typedef RequestEncoder = List<int> Function(
78 : String request, RequestOptions options);
79 :
80 : /// The common config for the Dio instance.
81 : /// `dio.options` is a instance of [BaseOptions]
82 : class BaseOptions extends _RequestConfig with OptionsMixin {
83 8 : BaseOptions({
84 : String? method,
85 : int? connectTimeout,
86 : int? receiveTimeout,
87 : int? sendTimeout,
88 : String baseUrl = '',
89 : Map<String, dynamic>? queryParameters,
90 : Map<String, dynamic>? extra,
91 : Map<String, dynamic>? headers,
92 : ResponseType? responseType = ResponseType.json,
93 : String? contentType,
94 : ValidateStatus? validateStatus,
95 : bool? receiveDataWhenStatusError,
96 : bool? followRedirects,
97 : int? maxRedirects,
98 : RequestEncoder? requestEncoder,
99 : ResponseDecoder? responseDecoder,
100 : ListFormat? listFormat,
101 : this.setRequestContentTypeWhenNoPayload = false,
102 8 : }) : super(
103 : method: method,
104 : receiveTimeout: receiveTimeout,
105 : sendTimeout: sendTimeout,
106 : extra: extra,
107 : headers: headers,
108 : responseType: responseType,
109 : contentType: contentType,
110 : validateStatus: validateStatus,
111 : receiveDataWhenStatusError: receiveDataWhenStatusError,
112 : followRedirects: followRedirects,
113 : maxRedirects: maxRedirects,
114 : requestEncoder: requestEncoder,
115 : responseDecoder: responseDecoder,
116 : listFormat: listFormat,
117 : ) {
118 16 : this.queryParameters = queryParameters ?? {};
119 8 : this.baseUrl = baseUrl;
120 8 : this.connectTimeout = connectTimeout ?? 0;
121 : }
122 :
123 : /// Create a Option from current instance with merging attributes.
124 1 : BaseOptions copyWith({
125 : String? method,
126 : String? baseUrl,
127 : Map<String, dynamic>? queryParameters,
128 : String? path,
129 : int? connectTimeout,
130 : int? receiveTimeout,
131 : int? sendTimeout,
132 : Map<String, dynamic>? extra,
133 : Map<String, dynamic>? headers,
134 : ResponseType? responseType,
135 : String? contentType,
136 : ValidateStatus? validateStatus,
137 : bool? receiveDataWhenStatusError,
138 : bool? followRedirects,
139 : int? maxRedirects,
140 : RequestEncoder? requestEncoder,
141 : ResponseDecoder? responseDecoder,
142 : ListFormat? listFormat,
143 : bool? setRequestContentTypeWhenNoPayload,
144 : }) {
145 1 : return BaseOptions(
146 1 : method: method ?? this.method,
147 1 : baseUrl: baseUrl ?? this.baseUrl,
148 1 : queryParameters: queryParameters ?? this.queryParameters,
149 1 : connectTimeout: connectTimeout ?? this.connectTimeout,
150 1 : receiveTimeout: receiveTimeout ?? this.receiveTimeout,
151 1 : sendTimeout: sendTimeout ?? this.sendTimeout,
152 2 : extra: extra ?? Map.from(this.extra),
153 2 : headers: headers ?? Map.from(this.headers),
154 1 : responseType: responseType ?? this.responseType,
155 1 : contentType: contentType ?? this.contentType,
156 1 : validateStatus: validateStatus ?? this.validateStatus,
157 : receiveDataWhenStatusError:
158 1 : receiveDataWhenStatusError ?? this.receiveDataWhenStatusError,
159 1 : followRedirects: followRedirects ?? this.followRedirects,
160 1 : maxRedirects: maxRedirects ?? this.maxRedirects,
161 1 : requestEncoder: requestEncoder ?? this.requestEncoder,
162 1 : responseDecoder: responseDecoder ?? this.responseDecoder,
163 1 : listFormat: listFormat ?? this.listFormat,
164 : setRequestContentTypeWhenNoPayload: setRequestContentTypeWhenNoPayload ??
165 1 : this.setRequestContentTypeWhenNoPayload,
166 : );
167 : }
168 :
169 : static const _allowPayloadMethods = ['POST', 'PUT', 'PATCH', 'DELETE'];
170 :
171 : /// if false, content-type in request header will be deleted when method is not on of `_allowPayloadMethods`
172 : bool setRequestContentTypeWhenNoPayload;
173 :
174 7 : String? contentTypeWithRequestBody(String method) {
175 7 : if (setRequestContentTypeWhenNoPayload) {
176 1 : return contentType;
177 : } else {
178 10 : return _allowPayloadMethods.contains(method) ? contentType : null;
179 : }
180 : }
181 : }
182 :
183 : mixin OptionsMixin {
184 : /// Request base url, it can contain sub path, like: "https://www.google.com/api/".
185 : late String baseUrl;
186 :
187 : /// Common query parameters.
188 : ///
189 : /// List values use the default [ListFormat.multiCompatible].
190 : ///
191 : /// The value can be overridden per parameter by adding a [MultiParam]
192 : /// object wrapping the actual List value and the desired format.
193 : late Map<String, dynamic> queryParameters;
194 :
195 : /// Timeout in milliseconds for opening url.
196 : /// [Dio] will throw the [DioError] with [DioErrorType.connectTimeout] type
197 : /// when time out.
198 : late int connectTimeout;
199 : }
200 :
201 : /// Every request can pass an [Options] object which will be merged with [Dio.options]
202 : class Options {
203 8 : Options({
204 : this.method,
205 : this.sendTimeout,
206 : this.receiveTimeout,
207 : this.extra,
208 : this.headers,
209 : this.responseType,
210 : this.contentType,
211 : this.validateStatus,
212 : this.receiveDataWhenStatusError,
213 : this.followRedirects,
214 : this.maxRedirects,
215 : this.requestEncoder,
216 : this.responseDecoder,
217 : this.listFormat,
218 : });
219 :
220 : /// Create a Option from current instance with merging attributes.
221 1 : Options copyWith({
222 : String? method,
223 : int? sendTimeout,
224 : int? receiveTimeout,
225 : Map<String, dynamic>? extra,
226 : Map<String, dynamic>? headers,
227 : ResponseType? responseType,
228 : String? contentType,
229 : ValidateStatus? validateStatus,
230 : bool? receiveDataWhenStatusError,
231 : bool? followRedirects,
232 : int? maxRedirects,
233 : RequestEncoder? requestEncoder,
234 : ResponseDecoder? responseDecoder,
235 : ListFormat? listFormat,
236 : }) {
237 : Map<String, dynamic>? _headers;
238 1 : if (headers == null && this.headers != null) {
239 2 : _headers = caseInsensitiveKeyMap(this.headers!);
240 : }
241 :
242 : if (headers != null) {
243 1 : headers = caseInsensitiveKeyMap(headers);
244 : assert(
245 0 : !(contentType != null &&
246 1 : headers.containsKey(Headers.contentTypeHeader)),
247 : 'You cannot set both contentType param and a content-type header',
248 : );
249 : }
250 :
251 : Map<String, dynamic>? _extra;
252 1 : if (extra == null && this.extra != null) {
253 0 : _extra = Map.from(this.extra!);
254 : }
255 :
256 1 : return Options(
257 1 : method: method ?? this.method,
258 1 : sendTimeout: sendTimeout ?? this.sendTimeout,
259 1 : receiveTimeout: receiveTimeout ?? this.receiveTimeout,
260 : extra: extra ?? _extra,
261 : headers: headers ?? _headers,
262 1 : responseType: responseType ?? this.responseType,
263 1 : contentType: contentType ?? this.contentType,
264 1 : validateStatus: validateStatus ?? this.validateStatus,
265 : receiveDataWhenStatusError:
266 1 : receiveDataWhenStatusError ?? this.receiveDataWhenStatusError,
267 1 : followRedirects: followRedirects ?? this.followRedirects,
268 1 : maxRedirects: maxRedirects ?? this.maxRedirects,
269 1 : requestEncoder: requestEncoder ?? this.requestEncoder,
270 1 : responseDecoder: responseDecoder ?? this.responseDecoder,
271 1 : listFormat: listFormat ?? this.listFormat,
272 : );
273 : }
274 :
275 8 : RequestOptions compose(
276 : BaseOptions baseOpt,
277 : String path, {
278 : data,
279 : Map<String, dynamic>? queryParameters,
280 : CancelToken? cancelToken,
281 : Options? options,
282 : ProgressCallback? onSendProgress,
283 : ProgressCallback? onReceiveProgress,
284 : }) {
285 8 : var query = <String, dynamic>{};
286 16 : query.addAll(baseOpt.queryParameters);
287 1 : if (queryParameters != null) query.addAll(queryParameters);
288 :
289 16 : var _headers = caseInsensitiveKeyMap(baseOpt.headers);
290 8 : _headers.remove(Headers.contentTypeHeader);
291 :
292 : String? _contentType;
293 :
294 8 : if (headers != null) {
295 4 : _headers.addAll(headers!);
296 2 : _contentType = _headers[Headers.contentTypeHeader] as String?;
297 : }
298 :
299 16 : var _extra = Map<String, dynamic>.from(baseOpt.extra);
300 8 : if (extra != null) {
301 0 : _extra.addAll(extra!);
302 : }
303 18 : var _method = (method ?? baseOpt.method).toUpperCase();
304 8 : var requestOptions = RequestOptions(
305 : method: _method,
306 : headers: _headers,
307 : extra: _extra,
308 8 : baseUrl: baseOpt.baseUrl,
309 : path: path,
310 : data: data,
311 8 : connectTimeout: baseOpt.connectTimeout,
312 16 : sendTimeout: sendTimeout ?? baseOpt.sendTimeout,
313 16 : receiveTimeout: receiveTimeout ?? baseOpt.receiveTimeout,
314 15 : responseType: responseType ?? baseOpt.responseType,
315 16 : validateStatus: validateStatus ?? baseOpt.validateStatus,
316 : receiveDataWhenStatusError:
317 16 : receiveDataWhenStatusError ?? baseOpt.receiveDataWhenStatusError,
318 16 : followRedirects: followRedirects ?? baseOpt.followRedirects,
319 16 : maxRedirects: maxRedirects ?? baseOpt.maxRedirects,
320 : queryParameters: query,
321 16 : requestEncoder: requestEncoder ?? baseOpt.requestEncoder,
322 16 : responseDecoder: responseDecoder ?? baseOpt.responseDecoder,
323 16 : listFormat: listFormat ?? baseOpt.listFormat,
324 : );
325 :
326 8 : requestOptions.onReceiveProgress = onReceiveProgress;
327 8 : requestOptions.onSendProgress = onSendProgress;
328 8 : requestOptions.cancelToken = cancelToken;
329 :
330 8 : requestOptions.contentType = _contentType ??
331 8 : contentType ??
332 7 : baseOpt.contentTypeWithRequestBody(_method);
333 : return requestOptions;
334 : }
335 :
336 : /// Http method.
337 : String? method;
338 :
339 : /// Http request headers. The keys of initial headers will be converted to lowercase,
340 : /// for example 'Content-Type' will be converted to 'content-type'.
341 : ///
342 : /// The key of Header Map is case-insensitive, eg: content-type and Content-Type are
343 : /// regard as the same key.
344 : Map<String, dynamic>? headers;
345 :
346 : /// Timeout in milliseconds for sending data.
347 : /// [Dio] will throw the [DioError] with [DioErrorType.sendTimeout] type
348 : /// when time out.
349 : int? sendTimeout;
350 :
351 : /// Timeout in milliseconds for receiving data.
352 : ///
353 : /// Note: [receiveTimeout] represents a timeout during data transfer! That is to say the
354 : /// client has connected to the server, and the server starts to send data to the client.
355 : ///
356 : /// [0] meanings no timeout limit.
357 : int? receiveTimeout;
358 :
359 : /// The request Content-Type. The default value is [ContentType.json].
360 : /// If you want to encode request body with 'application/x-www-form-urlencoded',
361 : /// you can set `ContentType.parse('application/x-www-form-urlencoded')`, and [Dio]
362 : /// will automatically encode the request body.
363 : String? contentType;
364 :
365 : /// [responseType] indicates the type of data that the server will respond with
366 : /// options which defined in [ResponseType] are `json`, `stream`, `plain`.
367 : ///
368 : /// The default value is `json`, dio will parse response string to json object automatically
369 : /// when the content-type of response is 'application/json'.
370 : ///
371 : /// If you want to receive response data with binary bytes, for example,
372 : /// downloading a image, use `stream`.
373 : ///
374 : /// If you want to receive the response data with String, use `plain`.
375 : ///
376 : /// If you want to receive the response data with original bytes,
377 : /// that's to say the type of [Response.data] will be List<int>, use `bytes`
378 : ResponseType? responseType;
379 :
380 : /// `validateStatus` defines whether the request is successful for a given
381 : /// HTTP response status code. If `validateStatus` returns `true` ,
382 : /// the request will be perceived as successful; otherwise, considered as failed.
383 : ValidateStatus? validateStatus;
384 :
385 : /// Whether receiving response data when http status code is not successful.
386 : /// The default value is true
387 : bool? receiveDataWhenStatusError;
388 :
389 : /// Custom field that you can retrieve it later in [Interceptor]、[Transformer] and the [Response] object.
390 : Map<String, dynamic>? extra;
391 :
392 : /// see [HttpClientRequest.followRedirects],
393 : /// The default value is true
394 : bool? followRedirects;
395 :
396 : /// Set this property to the maximum number of redirects to follow
397 : /// when [followRedirects] is `true`. If this number is exceeded
398 : /// an error event will be added with a [RedirectException].
399 : ///
400 : /// The default value is 5.
401 : int? maxRedirects;
402 :
403 : /// The default request encoder is utf8encoder, you can set custom
404 : /// encoder by this option.
405 : RequestEncoder? requestEncoder;
406 :
407 : /// The default response decoder is utf8decoder, you can set custom
408 : /// decoder by this option, it will be used in [Transformer].
409 : ResponseDecoder? responseDecoder;
410 :
411 : /// The [listFormat] indicates the format of collection data in request
412 : /// query parameters and `x-www-url-encoded` body data.
413 : /// Possible values defined in [ListFormat] are `csv`, `ssv`, `tsv`, `pipes`, `multi`, `multiCompatible`.
414 : /// The default value is `multi`.
415 : ListFormat? listFormat;
416 : }
417 :
418 : class RequestOptions extends _RequestConfig with OptionsMixin {
419 9 : RequestOptions({
420 : String? method,
421 : int? sendTimeout,
422 : int? receiveTimeout,
423 : int? connectTimeout,
424 : this.data,
425 : required this.path,
426 : Map<String, dynamic>? queryParameters,
427 : this.onReceiveProgress,
428 : this.onSendProgress,
429 : this.cancelToken,
430 : String? baseUrl,
431 : Map<String, dynamic>? extra,
432 : Map<String, dynamic>? headers,
433 : ResponseType? responseType,
434 : String? contentType,
435 : ValidateStatus? validateStatus,
436 : bool? receiveDataWhenStatusError,
437 : bool? followRedirects,
438 : int? maxRedirects,
439 : RequestEncoder? requestEncoder,
440 : ResponseDecoder? responseDecoder,
441 : ListFormat? listFormat,
442 : bool? setRequestContentTypeWhenNoPayload,
443 9 : }) : super(
444 : method: method,
445 : sendTimeout: sendTimeout,
446 : receiveTimeout: receiveTimeout,
447 : extra: extra,
448 : headers: headers,
449 : responseType: responseType,
450 : contentType: contentType,
451 : validateStatus: validateStatus,
452 : receiveDataWhenStatusError: receiveDataWhenStatusError,
453 : followRedirects: followRedirects,
454 : maxRedirects: maxRedirects,
455 : requestEncoder: requestEncoder,
456 : responseDecoder: responseDecoder,
457 : listFormat: listFormat,
458 : ) {
459 11 : this.queryParameters = queryParameters ?? {};
460 9 : this.baseUrl = baseUrl ?? '';
461 9 : this.connectTimeout = connectTimeout ?? 0;
462 : }
463 :
464 : /// Create a Option from current instance with merging attributes.
465 2 : RequestOptions copyWith({
466 : String? method,
467 : int? sendTimeout,
468 : int? receiveTimeout,
469 : int? connectTimeout,
470 : String? data,
471 : String? path,
472 : Map<String, dynamic>? queryParameters,
473 : String? baseUrl,
474 : ProgressCallback? onReceiveProgress,
475 : ProgressCallback? onSendProgress,
476 : CancelToken? cancelToken,
477 : Map<String, dynamic>? extra,
478 : Map<String, dynamic>? headers,
479 : ResponseType? responseType,
480 : String? contentType,
481 : ValidateStatus? validateStatus,
482 : bool? receiveDataWhenStatusError,
483 : bool? followRedirects,
484 : int? maxRedirects,
485 : RequestEncoder? requestEncoder,
486 : ResponseDecoder? responseDecoder,
487 : ListFormat? listFormat,
488 : bool? setRequestContentTypeWhenNoPayload,
489 : }) {
490 : var contentTypeInHeader = headers != null &&
491 1 : headers.keys
492 3 : .map((e) => e.toLowerCase())
493 1 : .contains(Headers.contentTypeHeader);
494 :
495 : assert(
496 1 : !(contentType != null && contentTypeInHeader),
497 : 'You cannot set both contentType param and a content-type header',
498 : );
499 :
500 2 : var ro = RequestOptions(
501 2 : method: method ?? this.method,
502 2 : sendTimeout: sendTimeout ?? this.sendTimeout,
503 2 : receiveTimeout: receiveTimeout ?? this.receiveTimeout,
504 2 : connectTimeout: connectTimeout ?? this.connectTimeout,
505 2 : data: data ?? this.data,
506 1 : path: path ?? this.path,
507 2 : baseUrl: baseUrl ?? this.baseUrl,
508 4 : queryParameters: queryParameters ?? Map.from(this.queryParameters),
509 2 : onReceiveProgress: onReceiveProgress ?? this.onReceiveProgress,
510 2 : onSendProgress: onSendProgress ?? this.onSendProgress,
511 2 : cancelToken: cancelToken ?? this.cancelToken,
512 4 : extra: extra ?? Map.from(this.extra),
513 4 : headers: headers ?? Map.from(this.headers),
514 2 : responseType: responseType ?? this.responseType,
515 2 : validateStatus: validateStatus ?? this.validateStatus,
516 : receiveDataWhenStatusError:
517 2 : receiveDataWhenStatusError ?? this.receiveDataWhenStatusError,
518 2 : followRedirects: followRedirects ?? this.followRedirects,
519 2 : maxRedirects: maxRedirects ?? this.maxRedirects,
520 2 : requestEncoder: requestEncoder ?? this.requestEncoder,
521 2 : responseDecoder: responseDecoder ?? this.responseDecoder,
522 2 : listFormat: listFormat ?? this.listFormat,
523 : );
524 :
525 : if (contentType != null) {
526 2 : ro.headers.remove(Headers.contentTypeHeader);
527 1 : ro.contentType = contentType;
528 : } else if (!contentTypeInHeader) {
529 4 : ro.contentType = this.contentType;
530 : }
531 :
532 : return ro;
533 : }
534 :
535 : /// generate uri
536 8 : Uri get uri {
537 8 : var _url = path;
538 16 : if (!_url.startsWith(RegExp(r'https?:'))) {
539 14 : _url = baseUrl + _url;
540 7 : var s = _url.split(':/');
541 14 : if (s.length == 2) {
542 35 : _url = s[0] + ':/' + s[1].replaceAll('//', '/');
543 : }
544 : }
545 24 : var query = Transformer.urlEncodeMap(queryParameters, listFormat);
546 8 : if (query.isNotEmpty) {
547 3 : _url += (_url.contains('?') ? '&' : '?') + query;
548 : }
549 : // Normalize the url.
550 16 : return Uri.parse(_url).normalizePath();
551 : }
552 :
553 : /// Request data, can be any type.
554 : ///
555 : /// When using `x-www-url-encoded` body data,
556 : /// List values use the default [ListFormat.multi].
557 : ///
558 : /// The value can be overridden per value by adding a [MultiParam]
559 : /// object wrapping the actual List value and the desired format.
560 : dynamic data;
561 :
562 : /// If the `path` starts with 'http(s)', the `baseURL` will be ignored, otherwise,
563 : /// it will be combined and then resolved with the baseUrl.
564 : String path;
565 :
566 : CancelToken? cancelToken;
567 :
568 : ProgressCallback? onReceiveProgress;
569 :
570 : ProgressCallback? onSendProgress;
571 : }
572 :
573 : /// The [_RequestConfig] class describes the http request information and configuration.
574 : class _RequestConfig {
575 9 : _RequestConfig({
576 : int? receiveTimeout,
577 : int? sendTimeout,
578 : String? method,
579 : Map<String, dynamic>? extra,
580 : Map<String, dynamic>? headers,
581 : String? contentType,
582 : ListFormat? listFormat,
583 : bool? followRedirects,
584 : int? maxRedirects,
585 : bool? receiveDataWhenStatusError,
586 : ValidateStatus? validateStatus,
587 : ResponseType? responseType,
588 : this.requestEncoder,
589 : this.responseDecoder,
590 : }) {
591 9 : this.headers = headers;
592 :
593 : var contentTypeInHeader =
594 18 : this.headers.containsKey(Headers.contentTypeHeader);
595 : assert(
596 0 : !(contentType != null && contentTypeInHeader) ||
597 3 : this.headers[Headers.contentTypeHeader] == contentType,
598 : 'You cannot set different values for contentType param and a content-type header',
599 : );
600 :
601 9 : this.method = method ?? 'GET';
602 9 : this.sendTimeout = sendTimeout ?? 0;
603 9 : this.receiveTimeout = receiveTimeout ?? 0;
604 9 : this.listFormat = listFormat ?? ListFormat.multi;
605 18 : this.extra = extra ?? {};
606 9 : this.followRedirects = followRedirects ?? true;
607 9 : this.maxRedirects = maxRedirects ?? 5;
608 9 : this.receiveDataWhenStatusError = receiveDataWhenStatusError ?? true;
609 9 : this.validateStatus = validateStatus ??
610 7 : (int? status) {
611 14 : return status != null && status >= 200 && status < 300;
612 : };
613 9 : this.responseType = responseType ?? ResponseType.json;
614 : if (!contentTypeInHeader) {
615 9 : this.contentType = contentType ?? Headers.jsonContentType;
616 : }
617 : }
618 :
619 : /// Http method.
620 : late String method;
621 :
622 : /// Http request headers. The keys of initial headers will be converted to lowercase,
623 : /// for example 'Content-Type' will be converted to 'content-type'.
624 : ///
625 : /// The key of Header Map is case-insensitive, eg: content-type and Content-Type are
626 : /// regard as the same key.
627 :
628 18 : Map<String, dynamic> get headers => _headers;
629 : late Map<String, dynamic> _headers;
630 :
631 9 : set headers(Map<String, dynamic>? headers) {
632 18 : _headers = caseInsensitiveKeyMap(headers);
633 9 : if (_defaultContentType != null &&
634 2 : !_headers.containsKey(Headers.contentTypeHeader)) {
635 3 : _headers[Headers.contentTypeHeader] = _defaultContentType;
636 : }
637 : }
638 :
639 : /// Timeout in milliseconds for sending data.
640 : /// [Dio] will throw the [DioError] with [DioErrorType.sendTimeout] type
641 : /// when time out.
642 : late int sendTimeout;
643 :
644 : /// Timeout in milliseconds for receiving data.
645 : ///
646 : /// Note: [receiveTimeout] represents a timeout during data transfer! That is to say the
647 : /// client has connected to the server, and the server starts to send data to the client.
648 : ///
649 : /// [0] meanings no timeout limit.
650 : late int receiveTimeout;
651 :
652 : /// The request Content-Type. The default value is [ContentType.json].
653 : /// If you want to encode request body with 'application/x-www-form-urlencoded',
654 : /// you can set `ContentType.parse('application/x-www-form-urlencoded')`, and [Dio]
655 : /// will automatically encode the request body.
656 9 : set contentType(String? contentType) {
657 : if (contentType != null) {
658 18 : _headers[Headers.contentTypeHeader] =
659 18 : _defaultContentType = contentType.trim();
660 : } else {
661 7 : _defaultContentType = null;
662 14 : _headers.remove(Headers.contentTypeHeader);
663 : }
664 : }
665 :
666 : String? _defaultContentType;
667 :
668 9 : String? get contentType => _headers[Headers.contentTypeHeader] as String?;
669 :
670 : /// [responseType] indicates the type of data that the server will respond with
671 : /// options which defined in [ResponseType] are `json`, `stream`, `plain`.
672 : ///
673 : /// The default value is `json`, dio will parse response string to json object automatically
674 : /// when the content-type of response is 'application/json'.
675 : ///
676 : /// If you want to receive response data with binary bytes, for example,
677 : /// downloading a image, use `stream`.
678 : ///
679 : /// If you want to receive the response data with String, use `plain`.
680 : ///
681 : /// If you want to receive the response data with original bytes,
682 : /// that's to say the type of [Response.data] will be List<int>, use `bytes`
683 : late ResponseType responseType;
684 :
685 : /// `validateStatus` defines whether the request is successful for a given
686 : /// HTTP response status code. If `validateStatus` returns `true` ,
687 : /// the request will be perceived as successful; otherwise, considered as failed.
688 : late ValidateStatus validateStatus;
689 :
690 : /// Whether receiving response data when http status code is not successful.
691 : /// The default value is true
692 : late bool receiveDataWhenStatusError;
693 :
694 : /// Custom field that you can retrieve it later in [Interceptor]、[Transformer] and the [Response] object.
695 : late Map<String, dynamic> extra;
696 :
697 : /// see [HttpClientRequest.followRedirects],
698 : /// The default value is true
699 : late bool followRedirects;
700 :
701 : /// Set this property to the maximum number of redirects to follow
702 : /// when [followRedirects] is `true`. If this number is exceeded
703 : /// an error event will be added with a [RedirectException].
704 : ///
705 : /// The default value is 5.
706 : late int maxRedirects;
707 :
708 : /// The default request encoder is utf8encoder, you can set custom
709 : /// encoder by this option.
710 : RequestEncoder? requestEncoder;
711 :
712 : /// The default response decoder is utf8decoder, you can set custom
713 : /// decoder by this option, it will be used in [Transformer].
714 : ResponseDecoder? responseDecoder;
715 :
716 : /// The [listFormat] indicates the format of collection data in request
717 : /// query parameters and `x-www-url-encoded` body data.
718 : /// Possible values defined in [ListFormat] are `csv`, `ssv`, `tsv`, `pipes`, `multi`, `multiCompatible`.
719 : /// The default value is `multi`.
720 : ///
721 : /// The value can be overridden per parameter by adding a [MultiParam]
722 : /// object to the query or body data map.
723 : late ListFormat listFormat;
724 : }
|