Flutter Chopper 401 更新和重试拦截器
Flutter Chopper 401 renew & retry interceptor
我在我的 flutter 应用程序中使用 Chopper,我需要做的是,当我从 API 收到 401 响应状态代码(未经授权)时,我必须调用另一个端点来刷新我的令牌并将其保存到安全存储中,当所有这些都完成后,我需要立即重试请求(这样用户就不会注意到他的令牌已过期)。这是仅适用于 Chopper,还是我必须使用其他软件包?
我搜索了几天的答案,我得出的结论是 Chopper 无法做到这一点...同时我切换到 Dio 作为我的网络客户端,但我使用 Chopper 来生成 functions/endpoints .
有可能。您需要在 Chopper 客户端上使用 authenticator 字段,例如
final ChopperClient client = ChopperClient(
baseUrl: backendUrl,
interceptors: [HeaderInterceptor()],
services: <ChopperService>[
_$UserApiService(),
],
converter: converter,
authenticator: MyAuthenticator(),
);
您的身份验证器 class 应如下所示:
class MyAuthenticator extends Authenticator {
@override
FutureOr<Request?> authenticate(
Request request, Response<dynamic> response) async {
if (response.statusCode == 401) {
String? newToken = await refreshToken();
final Map<String, String> updatedHeaders =
Map<String, String>.of(request.headers);
if (newToken != null) {
newToken = 'Bearer $newToken';
updatedHeaders.update('Authorization', (String _) => newToken!,
ifAbsent: () => newToken!);
return request.copyWith(headers: updatedHeaders);
}
}
return null;
}
诚然,find/understand 并不是那么容易(尽管它是他们的文档中提到的第一个 属性 chopper 客户端),但这正是 属性 是为了。我本来打算自己转到 dio,但在重试时我仍然遇到类型转换的问题。
编辑:您可能希望在某处保留重试计数,这样您就不会陷入循环。
这是我的身份验证器。仅供参考,我在首选项中存储 auth-token 和 refresh-token。
class AppAuthenticator extends Authenticator {
@override
FutureOr<Request?> authenticate(Request request, Response response, [Request? originalRequest]) async {
if (response.statusCode == HttpStatus.unauthorized) {
final client = CustomChopperClient.createChopperClient();
AuthorizationApiService authApi = client.getService<AuthorizationApiService>();
String refreshTokenValue = await Prefs.refreshToken;
Map<String, String> refreshToken = {'refresh_token': refreshTokenValue};
var tokens = await authApi.refresh(refreshToken);
final theTokens = tokens.body;
if (theTokens != null) {
Prefs.setAccessToken(theTokens.auth_token);
Prefs.setRefreshToken(theTokens.refresh_token);
request.headers.remove('Authorization');
request.headers.putIfAbsent('Authorization', () => 'Bearer ${theTokens.auth_token}');
return request;
}
}
return null;
}
}
基于这个例子:github
Chopper 客户端:
class CustomChopperClient {
static ChopperClient createChopperClient() {
final client = ChopperClient(
baseUrl: 'https://example.com/api/',
services: <ChopperService>[
AuthorizationApiService.create(),
ProfileApiService.create(),
AccountingApiService.create(), // and others
],
interceptors: [
HttpLoggingInterceptor(),
(Request request) async => request.copyWith(headers: {
'Accept': "application/json",
'Content-type': "application/json",
'locale': await Prefs.locale,
'Authorization': "Bearer ${await Prefs.accessToken}",
}),
],
converter: BuiltValueConverter(errorType: ErrorDetails),
errorConverter: BuiltValueConverter(errorType: ErrorDetails),
authenticator: AppAuthenticator(),
);
return client;
}
}
我在我的 flutter 应用程序中使用 Chopper,我需要做的是,当我从 API 收到 401 响应状态代码(未经授权)时,我必须调用另一个端点来刷新我的令牌并将其保存到安全存储中,当所有这些都完成后,我需要立即重试请求(这样用户就不会注意到他的令牌已过期)。这是仅适用于 Chopper,还是我必须使用其他软件包?
我搜索了几天的答案,我得出的结论是 Chopper 无法做到这一点...同时我切换到 Dio 作为我的网络客户端,但我使用 Chopper 来生成 functions/endpoints .
有可能。您需要在 Chopper 客户端上使用 authenticator 字段,例如
final ChopperClient client = ChopperClient(
baseUrl: backendUrl,
interceptors: [HeaderInterceptor()],
services: <ChopperService>[
_$UserApiService(),
],
converter: converter,
authenticator: MyAuthenticator(),
);
您的身份验证器 class 应如下所示:
class MyAuthenticator extends Authenticator {
@override
FutureOr<Request?> authenticate(
Request request, Response<dynamic> response) async {
if (response.statusCode == 401) {
String? newToken = await refreshToken();
final Map<String, String> updatedHeaders =
Map<String, String>.of(request.headers);
if (newToken != null) {
newToken = 'Bearer $newToken';
updatedHeaders.update('Authorization', (String _) => newToken!,
ifAbsent: () => newToken!);
return request.copyWith(headers: updatedHeaders);
}
}
return null;
}
诚然,find/understand 并不是那么容易(尽管它是他们的文档中提到的第一个 属性 chopper 客户端),但这正是 属性 是为了。我本来打算自己转到 dio,但在重试时我仍然遇到类型转换的问题。
编辑:您可能希望在某处保留重试计数,这样您就不会陷入循环。
这是我的身份验证器。仅供参考,我在首选项中存储 auth-token 和 refresh-token。
class AppAuthenticator extends Authenticator {
@override
FutureOr<Request?> authenticate(Request request, Response response, [Request? originalRequest]) async {
if (response.statusCode == HttpStatus.unauthorized) {
final client = CustomChopperClient.createChopperClient();
AuthorizationApiService authApi = client.getService<AuthorizationApiService>();
String refreshTokenValue = await Prefs.refreshToken;
Map<String, String> refreshToken = {'refresh_token': refreshTokenValue};
var tokens = await authApi.refresh(refreshToken);
final theTokens = tokens.body;
if (theTokens != null) {
Prefs.setAccessToken(theTokens.auth_token);
Prefs.setRefreshToken(theTokens.refresh_token);
request.headers.remove('Authorization');
request.headers.putIfAbsent('Authorization', () => 'Bearer ${theTokens.auth_token}');
return request;
}
}
return null;
}
}
基于这个例子:github
Chopper 客户端:
class CustomChopperClient {
static ChopperClient createChopperClient() {
final client = ChopperClient(
baseUrl: 'https://example.com/api/',
services: <ChopperService>[
AuthorizationApiService.create(),
ProfileApiService.create(),
AccountingApiService.create(), // and others
],
interceptors: [
HttpLoggingInterceptor(),
(Request request) async => request.copyWith(headers: {
'Accept': "application/json",
'Content-type': "application/json",
'locale': await Prefs.locale,
'Authorization': "Bearer ${await Prefs.accessToken}",
}),
],
converter: BuiltValueConverter(errorType: ErrorDetails),
errorConverter: BuiltValueConverter(errorType: ErrorDetails),
authenticator: AppAuthenticator(),
);
return client;
}
}