我的应用程序中有一个用于注销用户会话的按钮,当它被点击时,改装会向localhost发送一个基本的POST请求,从技术上说它已被注销,但如果我再次点击注销按钮,则会发生以下情况: / p>
第一次:一个请求通过 第二次点击注销:同时注销2个请求 第三次点击注销:注销3个请求
依旧......
老实说,这种情况对我来说非常令人费解,是的,我使用okhttp拦截器和一些令牌管理进行改造。
注意: - (Tinydb是一个简单的共享偏好管理器)
以下代码:
ApiInterfacer.java - 这是我的api界面
@FormUrlEncoded
@POST("/api/token/logout")
Call<BasicResponse> LOG_OUT(@Field("guid") String guid);
ApiService.java - 我的Api服务创建者
public class ApiService {
public static final String baseurl = StaticVars.LOCALHOST;
public static OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
private static Retrofit.Builder retrofitbuilder = new Retrofit.Builder().baseUrl(baseurl).addConverterFactory(GsonConverterFactory.create());
public static <S>S createService(Class<S> serviceClass , Context context) // service class is the REST class , ex : GithubClient
{
Retrofit retrofit = retrofitbuilder.build();
httpClientBuilder.interceptors().add(new ApiTokenInterceptor(context));
OkHttpClient client = httpClientBuilder.build();
retrofitbuilder.client(client);
return retrofit.create(serviceClass);
}
}
ApiTokenInterceptor.java
public class ApiTokenInterceptor implements Interceptor {
private final Context context;
public ApiTokenInterceptor(Context context){
this.context = context;
}
@Override
public Response intercept(Chain chain) throws IOException {
Log.i("INTERCEPT" , "FIRST " + chain.request().url());
TinyDB db = new TinyDB(context);
Request request = chain.request();
Request modifiedReq = request;
if(!db.getString("token").equals(""))
{
modifiedReq = request.newBuilder().addHeader("token" ,db.getString("token"))
.build();
}
Response response = chain.proceed(modifiedReq);
boolean unauthorized = response.code() == 401;
Log.i("INTERCEPT" , "SECOND - LOGOUT - PROCEED " + modifiedReq.url() + " " + unauthorized);
if(unauthorized){
response.body().close();
db.remove("token");
String refreshToken = db.getString("refken");
Request request1 = new Request.Builder()
.url(StaticVars.LOCALHOST + "/api/token")
.addHeader("refken" , refreshToken)
.get()
.build();
OkHttpClient client = new OkHttpClient();
Response response1 = client.newCall(request1).execute();
String response_string = response1.body().string();
Log.d("INTERCEPT" , "RESPONSE TOKEN STRING " + response_string);
try{
JSONObject object = new JSONObject(response_string);
String token = object.getString("token");
//set token to db
Log.d("TOKENB" , " "+token);
db.putString("token" , token);
}catch (JSONException e){
e.printStackTrace();
Log.d("INVALID RESPONSE" , " "+response_string);
db.putString("token" , "placeholder");
Log.i("INTERCEPT" , "AFINAL - LOGOUT - PROCEED " + modifiedReq.url());
return response;
}
modifiedReq = request.newBuilder().addHeader("token" , db.getString("token"))
.build();
Log.i("INTERCEPT" , "BFINAL - LOGOUT - PROCEED " + modifiedReq.url());
return chain.proceed(modifiedReq);
}
return response;
}
}
(使用).java - 使用按钮的onclicklistener
retro.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
//call retrofit :)
final ProgressDialog pd = new ProgressDialog(v.getContext());
pd.setMessage("Loading...");
pd.setCancelable(false);
pd.setIndeterminate(true);
pd.show();
ApiInterfacer client = ApiService.createService(ApiInterfacer.class, v.getContext());
Call<BasicResponse> call = client.LOG_OUT(db.getString("guid"));
call.enqueue(new Callback<BasicResponse>() {
@Override
public void onResponse(Call<BasicResponse> call, Response<BasicResponse> response) {
Log.d("Response : string" , "" + response.message());
switch(response.code())
{
case 401:
Log.d("LOGOUT" , "Unauthorized : "+401);
break;
case 400:
Log.d("LOGOUT" , "Malformed Body : " + 400);
break;
case 404:
Log.d("LOGOUT" , "URL Not Found :" + 404);
break;
case 200:
Log.d("Message" ,""+ response.body().getMessage()+" "+response.body().getCode());
if(response.body().getCode().equals("LOGGEDOUT"))
{
db.remove("token");
db.remove("refken");
startActivity(new Intent(getActivity(), LoginActivity.class));
getActivity().finish();
}
break;
default:
BasicResponse resp = response.body();
if(resp==null)
{
Log.d("Error" , "Response is null : " + response.code());
}else {
Log.d("Code", "" + resp.getCode());
Log.d("Source", "" + resp.getSource());
Log.d("Message", "" + resp.getMessage());
Log.d("Error", "" + resp.getError());
}
}
if(!call.isCanceled()) {
Log.i("INTERCEPT" , "FORCE CANCEL");
call.cancel();
}
pd.cancel();
}
@Override
public void onFailure(Call<BasicResponse> call, Throwable t) {
t.printStackTrace();
pd.cancel();
//page divert intent
Toast.makeText(v.getContext() , "Could not connect to server" , Toast.LENGTH_SHORT).show();
Log.d("FAIL" , ""+t.getMessage());
if(!call.isCanceled()) {
Log.i("INTERCEPT" , "FORCE CANCEL");
call.cancel();
}
}
});
}
});
日志: -
1st click : ( 0 * FIRST - Run at starting of interceptor ? interceptor not running ?? )
09-13 00:40:04.657 29600-29600/some.example.okhttp I/INTERCEPT: FORCE CANCEL
2nd click : ( 1 * FIRST - Run at starting of interceptor )
09-13 00:41:45.156 29600-31375/some.example.okhttp I/INTERCEPT: FIRST http://192.168.2.2/api/token/logout
09-13 00:41:45.166 29600-31375/some.example.okhttp I/INTERCEPT: SECOND - LOGOUT - PROCEED http://192.168.2.2/api/token/logout false
09-13 00:41:45.217 29600-29600/some.example.okhttp I/INTERCEPT: FORCE CANCEL
3rd click: ( 3 * FIRST )
09-13 00:41:54.364 29600-31375/some.example.okhttp I/INTERCEPT: FIRST http://192.168.2.2/api/token/logout
09-13 00:41:54.364 29600-31375/some.example.okhttp I/INTERCEPT: FIRST http://192.168.2.2/api/token/logout
09-13 00:41:54.370 29600-31375/some.example.okhttp I/INTERCEPT: SECOND - LOGOUT - PROCEED http://192.168.2.2/api/token/logout true
09-13 00:41:54.382 29600-31375/some.example.okhttp I/INTERCEPT: BFINAL - LOGOUT - PROCEED http://192.168.2.2/api/token/logout
09-13 00:41:54.431 29600-31375/some.example.okhttp I/INTERCEPT: SECOND - LOGOUT - PROCEED http://192.168.2.2/api/token/logout true
09-13 00:41:54.454 29600-31375/some.example.okhttp I/INTERCEPT: BFINAL - LOGOUT - PROCEED http://192.168.2.2/api/token/logout
09-13 00:41:54.454 29600-31375/some.example.okhttp I/INTERCEPT: FIRST http://192.168.2.2/api/token/logout
09-13 00:41:54.466 29600-31375/some.example.okhttp I/INTERCEPT: SECOND - LOGOUT - PROCEED http://192.168.2.2/api/token/logout true
09-13 00:41:54.503 29600-31375/some.example.okhttp I/INTERCEPT: BFINAL - LOGOUT - PROCEED http://192.168.2.2/api/token/logout
09-13 00:41:54.695 29600-29600/some.example.okhttp I/INTERCEPT: FORCE CANCEL
4th click: ( 7 * FIRST )
09-13 00:42:57.726 29600-32408/some.example.okhttp I/INTERCEPT: FIRST http://192.168.2.2/api/token/logout
09-13 00:42:57.726 29600-32408/some.example.okhttp I/INTERCEPT: FIRST http://192.168.2.2/api/token/logout
09-13 00:42:57.726 29600-32408/some.example.okhttp I/INTERCEPT: FIRST http://192.168.2.2/api/token/logout
09-13 00:42:57.731 29600-32408/some.example.okhttp I/INTERCEPT: SECOND - LOGOUT - PROCEED http://192.168.2.2/api/token/logout true
09-13 00:42:57.740 29600-32408/some.example.okhttp I/INTERCEPT: BFINAL - LOGOUT - PROCEED http://192.168.2.2/api/token/logout
09-13 00:42:57.779 29600-32408/some.example.okhttp I/INTERCEPT: SECOND - LOGOUT - PROCEED http://192.168.2.2/api/token/logout true
09-13 00:42:57.819 29600-32408/some.example.okhttp I/INTERCEPT: BFINAL - LOGOUT - PROCEED http://192.168.2.2/api/token/logout
09-13 00:42:57.819 29600-32408/some.example.okhttp I/INTERCEPT: FIRST http://192.168.2.2/api/token/logout
09-13 00:42:57.831 29600-32408/some.example.okhttp I/INTERCEPT: SECOND - LOGOUT - PROCEED http://192.168.2.2/api/token/logout true
09-13 00:42:57.865 29600-32408/some.example.okhttp I/INTERCEPT: BFINAL - LOGOUT - PROCEED http://192.168.2.2/api/token/logout
09-13 00:42:57.892 29600-32408/some.example.okhttp I/INTERCEPT: SECOND - LOGOUT - PROCEED http://192.168.2.2/api/token/logout true
09-13 00:42:57.942 29600-32408/some.example.okhttp I/INTERCEPT: BFINAL - LOGOUT - PROCEED http://192.168.2.2/api/token/logout
09-13 00:42:57.942 29600-32408/some.example.okhttp I/INTERCEPT: FIRST http://192.168.2.2/api/token/logout
09-13 00:42:57.942 29600-32408/some.example.okhttp I/INTERCEPT: FIRST http://192.168.2.2/api/token/logout
09-13 00:42:57.968 29600-32408/some.example.okhttp I/INTERCEPT: SECOND - LOGOUT - PROCEED http://192.168.2.2/api/token/logout true
09-13 00:42:58.006 29600-32408/some.example.okhttp I/INTERCEPT: BFINAL - LOGOUT - PROCEED http://192.168.2.2/api/token/logout
09-13 00:42:58.029 29600-32408/some.example.okhttp I/INTERCEPT: SECOND - LOGOUT - PROCEED http://192.168.2.2/api/token/logout true
09-13 00:42:58.053 29600-32408/some.example.okhttp I/INTERCEPT: BFINAL - LOGOUT - PROCEED http://192.168.2.2/api/token/logout
09-13 00:42:58.053 29600-32408/some.example.okhttp I/INTERCEPT: FIRST http://192.168.2.2/api/token/logout
09-13 00:42:58.086 29600-32408/some.example.okhttp I/INTERCEPT: SECOND - LOGOUT - PROCEED http://192.168.2.2/api/token/logout true
09-13 00:42:58.152 29600-32408/some.example.okhttp I/INTERCEPT: BFINAL - LOGOUT - PROCEED http://192.168.2.2/api/token/logout
09-13 00:42:58.245 29600-29600/some.example.okhttp I/INTERCEPT: FORCE CANCEL
答案 0 :(得分:1)
每次创建Retrofit服务时,请再次安装您的服务,这可能会导致问题。
尝试制作一个返回factory
服务的singleton
:
private static AmazonServices amazonServices = null;
private static PurpleServices purpleServices = null;
static OkHttpClient.Builder httpClient = getUnsafeOkHttpClient();
private static Retrofit.Builder builder = new Retrofit.Builder();
public static <S> S createService(Class<S> serviceClass) {
S mAPI = null;
if (serviceClass.getSimpleName().equals("PurpleService")) {
if (purpleServices == null) {
purpleServices = (PurpleServices) createPurpleAPI(serviceClass);
}
mAPI = (S) purpleServices;
} else if (serviceClass.getSimpleName().equals("AmazonServices")) {
if (amazonServices == null) {
amazonServices = (AmazonServices) createAmazonAPI(serviceClass);
}
mAPI = (S) amazonServices;
}
return mAPI;
}
你这样称呼它:
private AmazonServices amazonServices = RetrofitCreator.createService(AmazonServices.class);