gpt4 book ai didi

java - REST 方法 - 在其他方法之前执行 "common"方法调用

转载 作者:太空宇宙 更新时间:2023-11-04 11:36:56 25 4
gpt4 key购买 nike

我有一个 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com