Files
platforms/apps/service_app/lib/data/services/api_client.dart

106 lines
3.4 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:image_picker/image_picker.dart';
class ApiException implements Exception {
const ApiException(this.code, this.message);
final int code;
final String message;
@override
String toString() => message;
}
class ApiClient {
ApiClient(this._tokenProvider, {http.Client? client, String? baseUrl})
: _client = client ?? http.Client(),
baseUrl =
baseUrl ??
const String.fromEnvironment(
'API_BASE_URL',
defaultValue: 'http://10.0.2.2:12426',
);
final String baseUrl;
final String Function() _tokenProvider;
final http.Client _client;
Future<Object?> get(String path, {bool authenticated = true}) =>
_send('GET', path, authenticated: authenticated);
Future<Object?> post(
String path, {
Map<String, Object?>? body,
bool authenticated = true,
}) => _send('POST', path, body: body, authenticated: authenticated);
Future<Object?> put(String path, {Map<String, Object?>? body}) => _send('PUT', path, body: body);
/// 上传跨平台文件对象;浏览器端不能依赖本地文件路径。
Future<String> upload(XFile file, {String contentType = 'image/jpeg'}) async {
final request = http.MultipartRequest(
'POST',
Uri.parse('$baseUrl/upload/file'),
);
request.headers['authorization'] = _tokenProvider();
request.fields['declared_content_type'] = contentType;
request.files.add(
http.MultipartFile.fromBytes(
'file',
await file.readAsBytes(),
filename: file.name,
),
);
final response = await http.Response.fromStream(await request.send());
final details = _decode(response);
return jsonMap(details)['uri'] as String? ?? '';
}
Future<Object?> _send(
String method,
String path, {
Map<String, Object?>? body,
bool authenticated = true,
}) async {
final request = http.Request(method, Uri.parse('$baseUrl$path'));
request.headers['accept'] = 'application/json';
if (authenticated && _tokenProvider().isNotEmpty) {
request.headers['authorization'] = _tokenProvider();
}
if (body != null) {
request.headers['content-type'] = 'application/json; charset=UTF-8';
request.body = jsonEncode(body);
}
final response = await http.Response.fromStream(
await _client.send(request),
);
return _decode(response);
}
Object? _decode(http.Response response) {
if (response.statusCode < 200 || response.statusCode >= 300) {
throw ApiException(response.statusCode, '网络请求失败(${response.statusCode}');
}
final decoded = jsonDecode(response.body);
if (decoded is! Map<String, Object?>) {
throw const ApiException(500, '服务端响应格式错误');
}
final code = (decoded['code'] as num?)?.toInt() ?? 500;
if (code != 0) throw ApiException(code, decoded['message'] as String? ?? '操作失败');
return decoded['details'];
}
}
Map<String, Object?> jsonMap(Object? value) {
if (value is Map<String, Object?>) return value;
if (value is Map) return value.map((key, item) => MapEntry(key.toString(), item));
throw const ApiException(500, '服务端数据格式错误');
}
List<Map<String, Object?>> jsonList(Object? value) {
if (value is! List) return const [];
return value.map<Map<String, Object?>>(jsonMap).toList(growable: false);
}