send method
Sends an HTTP request and asynchronously returns the response.
Implementers should call BaseRequest.finalize to get the body of the
request as a ByteStream. They shouldn't make any assumptions about the
state of the stream; it could have data written to it asynchronously at a
later point, or it could already be closed when it's returned. Any
internal HTTP errors should be wrapped as ClientExceptions.
Implementation
@override
Future<http.StreamedResponse> send(http.BaseRequest request) async {
final client = activeInnerClient;
final key = request.url.toString();
// Handle GET request caching
if (request.method == 'GET') {
final cached = _cache[key];
if (cached != null && !cached.isExpired(ttl)) {
stats.hits++;
// Refresh position in LinkedHashMap to keep LRU order
_cache.remove(key);
_cache[key] = cached;
onCacheHit?.call(key, stats);
return http.StreamedResponse(
Stream.value(cached.bytes),
cached.statusCode,
headers: cached.headers,
contentLength: cached.bytes.length,
request: request,
);
}
stats.misses++;
}
final response = await client.send(request);
// Cache successful GET responses
if (request.method == 'GET' && response.statusCode == 200) {
final bytes = await response.stream.toBytes();
_putInCache(
key,
CachedHttpResponse(
bytes: bytes,
statusCode: response.statusCode,
headers: response.headers,
createdAt: DateTime.now(),
),
);
return http.StreamedResponse(
Stream.value(bytes),
response.statusCode,
headers: response.headers,
contentLength: response.contentLength,
reasonPhrase: response.reasonPhrase,
isRedirect: response.isRedirect,
persistentConnection: response.persistentConnection,
request: response.request,
);
}
// Check if the request is a mutating operation
if (isMutatingRequest(request) && response.statusCode < 400) {
_applyInvalidation(request);
}
return response;
}