Dio对象在App请求中一般在单例对象中使用,用来与后端进行普通的网络请求,如POST\GET等。Dio支持使用拦截器对所有的请求进行拦截,从而进行特殊处理,如增加token参数、请求和响应日志记录等。参考代码片段:
引用头文件:
import 'package:dio/dio.dart';
import 'interceptor/http_interceptor.dart';
在类的构造中,添加自定义的拦截器:
class ThingsboardClient {
///......
factory ThingsboardClient() {
var dio = Dio();
dio.options.baseUrl = apiEndpoint;
dio.interceptors.clear();
dio.interceptors.add(HttpInterceptor());
///......
}
自定义的拦截器,拦截所有的API类型的请求,并添加token:
class HttpInterceptor extends Interceptor {
static const String _authScheme = 'Bearer ';
static const _authHeaderName = 'X-Authorization';
///...
@override
Future onRequest(
RequestOptions options, RequestInterceptorHandler handler) async {
if (options.path.startsWith('/api/')) {
var config = _getInterceptorConfig(options);
var isLoading = !_isInternalUrlPrefix(options.path);
if (!config.isRetry) {
_updateLoadingState(config, isLoading);
}
///路径是否需要token
if (_isTokenBasedAuthEntryPoint(options.path)) {
///token是否有效
if (_tbClient.getJwtToken() == null &&
!_tbClient.refreshTokenPending()) {
return _handleRequestError(
options, handler, ThingsboardError(message: 'Unauthorized!'));
} else if (!_tbClient.isJwtTokenValid()) {
///token不可用,返回错误,刷新token后,重新提交请求
return _handleRequestError(
options, handler, ThingsboardError(refreshTokenPending: true));
} else {
///处理请求,添加token等头信息
return _jwtIntercept(options, handler);
}
} else {
return _handleRequest(options, handler);
}
} else {
return handler.next(options);
}
}
///需要启用token的路径
bool _isTokenBasedAuthEntryPoint(String url) {
return url.startsWith('/api/') &&
!url.startsWith(Constants.entryPoints['login']!) &&
!url.startsWith(Constants.entryPoints['tokenRefresh']!) &&
!url.startsWith(Constants.entryPoints['nonTokenBased']!);
}
bool _updateAuthorizationHeader(RequestOptions options) {
var jwtToken = _tbClient.getJwtToken();
if (jwtToken != null) {
options.headers[_authHeaderName] = _authScheme + jwtToken;
return true;
} else {
return false;
}
}
Future _jwtIntercept(
RequestOptions options, RequestInterceptorHandler handler) async {
///更新头授权token等信息
if (_updateAuthorizationHeader(options)) {
return _handleRequest(options, handler);
} else {
return _handleRequestError(options, handler,
ThingsboardError(message: 'Could not get JWT token from store.'));
}
}
///...
}
封装后的 get、post、delete代码示例:?
Future<Response<T>> get<T>(
String path, {
Map<String, dynamic>? queryParameters,
Options? options,
CancelToken? cancelToken,
ProgressCallback? onReceiveProgress,
}) async {
try {
return await _dio.get(path,
queryParameters: queryParameters,
options: options,
cancelToken: cancelToken,
onReceiveProgress: onReceiveProgress);
} catch (e) {
throw toThingsboardError(e);
}
}
Future<Response<T>> post<T>(
String path, {
data,
Map<String, dynamic>? queryParameters,
Options? options,
CancelToken? cancelToken,
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
try {
return await _dio.post(path,
data: data,
queryParameters: queryParameters,
options: options,
cancelToken: cancelToken,
onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress);
} catch (e) {
throw toThingsboardError(e);
}
}
Future<Response<T>> delete<T>(
String path, {
data,
Map<String, dynamic>? queryParameters,
Options? options,
CancelToken? cancelToken,
}) async {
try {
return await _dio.delete(path,
data: data,
queryParameters: queryParameters,
options: options,
cancelToken: cancelToken);
} catch (e) {
throw toThingsboardError(e);
}
}
定义请求和应答对象:
class LoginRequest {
String username;
String password;
LoginRequest(this.username, this.password);
Map<String, dynamic> toJson() {
return {
'username': username,
'password': password,
};
}
}
class LoginResponse {
final String token;
final String refreshToken;
LoginResponse(this.token, this.refreshToken);
LoginResponse.fromJson(Map<String, dynamic> json)
: token = json['token'],
refreshToken = json['refreshToken'];
}
提交请求(代码中为用户登录,并获取token和refreshToken):
Future<LoginResponse> login(LoginRequest loginRequest,
{RequestConfig? requestConfig}) async {
var response = await post('/api/auth/login',
data: jsonEncode(loginRequest),
options: defaultHttpOptionsFromConfig(requestConfig));
var loginResponse = LoginResponse.fromJson(response.data);
await _setUserFromJwtToken(
loginResponse.token, loginResponse.refreshToken, true);
return loginResponse;
}
|