- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我有一个 Android 应用程序,它调用 REST
API。 REST API 使用 JWT
进行保护,当用户登录应用程序时,我会获取 android 的 token 。 token 将在 60 分钟后过期。
在我的 Android 应用程序中,我有不同的类,它们总共包含 50-60 个 REST 调用。 Android 应用程序使用 Retrofit
连接到这些 REST 方法。我有一些方法需要在执行另一个方法后才能工作,这些方法位于第一个方法的 onResponse
方法中。
我编写了一个名为 Token
的特殊类,它从变量中设置
并获取
JWT token 。每个 REST 调用都从此类获取 token 。
无论如何,由于 REST 使用 JWT
进行保护,我必须在 50 分钟后重新更新 token 。我首先必须检查Token
类中的token
变量是否即将过期,它有一个特殊的方法whenWillExpire()
来告诉我 token 何时过期。如果是,则再次调用REST API并获取新的 token 。
情况是,由于我无法判断必须在哪个 REST 调用上重新更新 token ,因此我必须在任何
REST 调用之前执行此 token 过期检查,并在调用所选 REST 方法之前获取新 token (如果过期)。举个例子,假设我有一个名为 renew()
的方法,它检查 token 并通过执行 REST 工作从服务器获取它。任何其他 REST 调用都应在执行 renew()
完成后运行。 renew()
应在每个 REST 调用请求上首先运行。以下是此方法的示例。
private void renew(String token) {
if(token expired){
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss")
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(RestCommon.URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
GetNewToken endPoint = retrofit.create(GetNewToken.class);
Call<ResponseBody> call = endPoint.getNewToken();
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Response<ResponseBody> response, Retrofit retrofit) {
// Good. Now we have the token. Call other methods here.
}
@Override
public void onFailure(Throwable t) {
t.printStackTrace();
}
});
}
else
{
//Not expired. Call other methods.
}
}
那么,在执行请求的方法之前,如何确保 renew()
在每个 REST 请求中运行?对此最好的设计是什么?我有大约 50-60 个 REST 方法,用不同的名称复制上述代码并在其中添加其他 REST 调用绝对不是一个好的模式。
最佳答案
定义所有 API 端点:
public interface MyApi {
@GET("item/{id}")
Call<Item> getItemById(@Path("id") String id, @Header("Authorization") String auth)
@DELETE("item/{id}")
Call<String> deleteItemById(@Path("id") String id, @Header("Authorization") String auth)
@POST("auth")
Call<String> getNewToken(@Field("token") String currentToken);// or other params needed by getNewToken
//...etc
}
包装类:
public class MyApiManager{ //?? chose other name if u want :)
private MyApi myApi = null;
private static MyApiManager instance = null;
public MyApiManager getInstance(){
if(instance == null){
instance = new MyApiManager();
}
return instance;
}
private MyApiManager(){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.host.name")
//other setting before build() ...
.build();
myApi = retrofit.create(MyApi.class);
}
//-------- General methods, like check token expired...
private boolean checkAndGetNewToken(){
if(token expired){
Thread t = new Thread(new Runnable() {
@Override
public void run() {
//note here using myApi directly to avoid recursive calls for checkAndGetNewToken()
Response<String> response = myApi.getNewToken(token).execute();
Token.set(response);//update your token
}//run()
});
t.start();
t.join();
}//token exp
return true;
}//checkToken
//------ wrapper methods for each API endpoint
public Call<Item> getItemById(String id) throws TokenExpiredException{
checkTokenExpiration();
return myApi.getItemById(id, "Authorization:Bearer "+Token.get());
}
public Call<Item> deleteItemById(String id) throws TokenExpiredException{
checkTokenExpiration();
return myApi.deleteItemById(id, "Authorization:Bearer "+Token.get());
}
public Call<Item> getNewToken(String currentToken) throws TokenExpiredException{
checkTokenExpiration();
return myApi.getNewToken(currentToken);
}
}
使用示例:
public class SomeClass {
public void someMethod(){
MyApiManager.getInstance().getItem("102").enqueue(new Callback<Item>() {
@Override
public void onResponse(Response<Item> response, Retrofit retrofit) {
callApiStageB(response.getBody().getId()); //?
}
@Override
public void onFailure(Throwable t) {
t.printStackTrace();
//show a toast ...
}
});
}
public void callApiStageB(String id){
MyApiManager.getInstance().deleteItemById(id).enqueue(new Callback<String>() {
@Override
public void onResponse(Response<String> response, Retrofit retrofit) {
//....more nested api-calls, or do anything else
}
@Override
public void onFailure(Throwable t) {
t.printStackTrace();
//show a toast ...
}
});
}
}
如您所见,每次使用 apiManager 的调用都会首先检查/请求新 token ,问题是当需要新 token 时,这部分已处理,但是在执行此步骤后如何返回并执行原始请求(例如 getItem()),因为它应该通过 enqueue()
和 CallBack
我为此建议的 sol(Thread 和 join())很脏,我认为它会抛出一些异常,例如 NetworkOnMainThread
...希望这对您有任何帮助:)
关于java - REST 方法 - 在其他方法之前执行 "common"方法调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43182117/
我正在寻找一种使此打印 HTML 代码 fragment 向后兼容旧 Android 版本的简单方法: @TargetApi(Build.VERSION_CODES.KITKAT) private v
我在 GCC 终端 (centos linux) 中为 ATM 项目编译以下 c 和 .h 代码时收到以下错误。请帮忙,因为我是编程新手。 validate_acc.h #ifndef _VALIDA
在写关于 SO 的不同问题的答案时,我制作了这个片段: @import url('https://fonts.googleapis.com/css?family=Shadows+Into+Light'
试图弄清楚我应该如何在 my_div_class 之前放置一个 span 而不是替换所有它。现在它取代了 div,但我不想这样做。我假设它类似于 :before 但不知道如何使用它。 { va
我正在使用选择库 http://github.hubspot.com/select/和 noUiSlider https://refreshless.com/nouislider/ .我面临的问题如下
我是开发新手,独自工作。我正在使用 Xcode 和 git 版本控制。可能我没有适本地组织和做错事,但我通常决定做 promise 只是为了在我破坏一切之前做出安全点。在那一刻,我发现很难恰本地描述我
我想确保在同一个桶和键上读取和写入时,应该更新获取的值,也就是说,应该在对其进行写入操作之后获取它。我怎样才能做到这一点? 我想要的是,如果我更新一个键的值,如果我同时使用不同线程获取值,则更新同一个
我的问题与this有关问题,已经有了答案: yes, there is a happens-before relationship imposed between actionsof the thre
The before and after hook documentation on Relish仅显示 before(:suite) 在 before(:all) 之前调用。 我什么时候应该使用其中
我有 CSV 行,我想在其中检测所有内部双引号,没有文本限定符。这几乎可以正常工作,但我的正则表达式还可以检测双引号后的字符。 CSV 部分: "7580";"Lorem ipsum";"";"Lor
是否可以通过Youtube数据API检查广告是否可以与特定视频一起显示? 我了解contentDetails.licensedContent仅显示视频是否已上传至同一伙伴然后由其声明版权。由于第三者权
考虑一下用漂亮的彩色图表描述的“像素管道” https://developers.google.com/web/fundamentals/performance/rendering/ 我有一个元素(比
之前?
在 MVC3 中,我可以轻松地将 jQuery 脚本标签移动到页面底部“_Layout.vbhtml” 但是,在 ASP.NET MVC3 中,当您使用编辑器模板创建 Controller 时,脚手
悬停时内容被替换,但是当鼠标离开元素时我希望它变回来。我该怎么做? $('.img-wrap').hover(function(){ $(this).find('h4').text('Go
已关闭。这个问题是 not reproducible or was caused by typos 。目前不接受答案。 这个问题是由拼写错误或无法再重现的问题引起的。虽然类似的问题可能是 on-top
已关闭。这个问题是 not reproducible or was caused by typos 。目前不接受答案。 这个问题是由拼写错误或无法再重现的问题引起的。虽然类似的问题可能是 on-top
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 已关闭 9 年前。 有关您编写的代码问题的问题必须在问题本身中描述具体问题 - 并包含有效代码以重现该问题。
版本:qwt 6.0.1我尝试开发频谱的对数缩放。我使用简单的线条来启用缩放plotspectrum->setAxisScaleEngine(QwtPlot::yLeft, new QwtLog10S
我有两个相同的表,I_Subject 和 I_Temp_Subject,我想将 Temp_Subject 表复制到 Subject 表。 I_Temp_Subject 由简单用户使用,I_Subjec
我的印象是第一次绘制发生在触发 DOMContentLoaded 事件之后。特别是,因为我认为为了让第一次绘制发生,需要渲染树,它依赖于 DOM 构造。另外,我知道 DOM 构造完成时会触发 DOMC
我是一名优秀的程序员,十分优秀!