request method
Executes an HTTP request.
This is the core method that performs the actual HTTP request using the underlying HTTP client library.
Parameters:
- request: The request configuration containing URL, method, headers, body, etc.
Returns a Future that completes with an AdapterResponse containing the response data, status code, headers, etc.
Throws AdapterException if the request fails due to timeout, network error, or other issues.
Example:
final request = AdapterRequest(
baseUrl: 'https://api.example.com',
path: '/users/123',
method: HttpMethod.get,
);
final response = await adapter.request(request);
print('Status: ${response.statusCode}');
print('Data: ${response.data}');
Implementation
@override
Future<AdapterResponse> request(AdapterRequest request) async {
final completer = Completer<void>();
adapter_cancel.CancelToken? activeCancelToken;
try {
var modifiedRequest = request;
for (final interceptor in _interceptors) {
final handler = RequestInterceptorHandler();
interceptor.onRequest(modifiedRequest, handler);
if (handler.resolvedResponse != null) {
return handler.resolvedResponse!;
}
if (handler.rejectedError != null) {
throw handler.rejectedError!;
}
if (handler.modifiedRequest != null) {
modifiedRequest = handler.modifiedRequest!;
}
}
activeCancelToken = modifiedRequest.cancelToken;
if (activeCancelToken != null) {
_registerCancelToken(activeCancelToken, completer);
if (activeCancelToken.isCancelled) {
throw AdapterException(
type: AdapterExceptionType.cancel,
message: activeCancelToken.cancelReason ?? 'Request cancelled',
);
}
}
final baseRequest = await _buildBaseRequest(modifiedRequest);
// --- 超时策略 ---
// connectTimeout 包裹 send() 阶段(建连 + 获取响应头)
// receiveTimeout 包裹 Response.fromStream() 阶段(读取响应体)
// 两者独立作用,互不干扰
var sendFuture = _client.send(baseRequest);
final connectTimeout = _baseOptions?.connectTimeout;
if (connectTimeout != null && connectTimeout.inMilliseconds > 0) {
sendFuture = sendFuture.timeout(
connectTimeout,
onTimeout: () => throw AdapterException(
type: AdapterExceptionType.connectionError,
message: 'Connect timeout after ${connectTimeout.inSeconds}s',
),
);
}
final streamedResponse = activeCancelToken != null
? await Future.any<http.StreamedResponse>([
sendFuture,
completer.future.then((_) => throw AdapterException(
type: AdapterExceptionType.cancel,
message:
activeCancelToken!.cancelReason ?? 'Request cancelled',
)),
])
: await sendFuture;
// --- receiveDataWhenStatusError 控制 ---
// 当状态码表示错误且 receiveDataWhenStatusError 为 false 时,
// 不读取响应体以节省带宽
final isErrorResponse =
streamedResponse.statusCode >= 400;
final shouldReadBody = !isErrorResponse ||
(_baseOptions?.receiveDataWhenStatusError ?? true);
var response = modifiedRequest.responseType == ResponseType.stream
? _convertFromHttpStreamedResponse(streamedResponse, modifiedRequest)
: _convertFromHttpResponse(
shouldReadBody
? await _readResponseWithTimeout(streamedResponse)
: http.Response('', streamedResponse.statusCode,
headers: streamedResponse.headers),
modifiedRequest,
);
if (!response.isSuccess) {
final exception = AdapterException(
message:
'HTTP ${response.statusCode}: ${response.statusMessage ?? ""}',
type: AdapterExceptionType.response,
statusCode: response.statusCode,
response: response,
);
// 执行错误拦截器
var modifiedException = exception;
for (final interceptor in _interceptors) {
final handler = ErrorInterceptorHandler();
interceptor.onError(modifiedException, handler);
if (handler.resolvedResponse != null) {
return handler.resolvedResponse!;
}
if (handler.modifiedError != null) {
modifiedException = handler.modifiedError!;
}
}
throw modifiedException;
}
for (final interceptor in _interceptors) {
final handler = ResponseInterceptorHandler();
interceptor.onResponse(response, handler);
if (handler.rejectedError != null) {
throw handler.rejectedError!;
}
if (handler.modifiedResponse != null) {
response = handler.modifiedResponse!;
}
}
return response;
} on AdapterException {
rethrow;
} catch (e, stackTrace) {
var exception = _convertException(e, stackTrace);
for (final interceptor in _interceptors) {
final handler = ErrorInterceptorHandler();
interceptor.onError(exception, handler);
if (handler.resolvedResponse != null) {
return handler.resolvedResponse!;
}
if (handler.modifiedError != null) {
exception = handler.modifiedError!;
}
}
throw exception;
} finally {
_unregisterCancelToken(activeCancelToken, completer);
}
}