send method
Implementation
@override
Future<ResponseOptions> send(RequestOptions options) async {
if (options.cancelToken?.isCancelled == true) {
throw RequestCancelledException(options.cancelToken!.reason!);
}
final xhr = html.HttpRequest();
final url = options.uri.toString();
final completer = Completer<ResponseOptions>();
xhr
..open(options.method, url, async: true)
..responseType = 'text';
// timeout (ms)
if (options.timeout != null) {
xhr.timeout = options.timeout!.inMilliseconds;
}
// headers
options.headers.forEach((k, v) => xhr.setRequestHeader(k, v));
// events
xhr.onError.listen((_) {
if (!completer.isCompleted) {
completer.completeError(NetworkException("Network error"));
}
});
xhr.onTimeout.listen((_) {
if (!completer.isCompleted) {
completer.completeError(QuickTimeoutException());
}
});
xhr.onReadyStateChange.listen((_) {
if (xhr.readyState == html.HttpRequest.DONE && !completer.isCompleted) {
final status = xhr.status;
final ct = xhr.getResponseHeader('content-type') ?? '';
final txt = xhr.responseText ?? '';
dynamic data;
if (ct.contains('application/json')) {
try {
data = jsonDecode(txt);
} catch (_) {
data = txt;
}
} else {
data = txt.isEmpty ? null : txt;
}
completer.complete(ResponseOptions(
statusCode: status!,
data: data,
requestOptions: options,
));
}
});
// cancel
if (options.cancelToken != null) {
// Basit iptal: token tetiklenirse abort
unawaited(_watchCancel(options.cancelToken!, xhr, completer));
}
// body
dynamic sendData;
if (options.body != null) {
if (options.body is String) {
sendData = options.body as String;
} else if (options.body is List<int>) {
sendData = html.Blob([options.body as List<int>]);
} else {
// JSON
final hasCT = options.headers.keys.any(
(k) => k.toLowerCase() == 'content-type',
);
if (!hasCT) {
xhr.setRequestHeader('Content-Type', 'application/json');
}
sendData = jsonEncode(options.body);
}
}
try {
xhr.send(sendData);
} catch (e) {
if (!completer.isCompleted) {
completer.completeError(NetworkException(e.toString()));
}
}
return completer.future;
}