- 什么是 token;
- 为什么要使用 token;
- 在 Android 中应该如何使用 token;
ok,今天的学习是围绕着上面的问题来进行的。那么我们一个一个来解决。
什么是 token
首先,从字面上理解,token 是令牌的意思。在开发中,token 则是由服务器通过一些特定的算法生成的字符串,是客户端和服务端交互的令牌。token 生成之后会发送给客户端,客户端收到 token 之后,它每次与服务器交互都需要携带 token,否则服务器就会返回错误码。
题外话:在实战中,返回的错误码都是由后端编程人员决定的,而我们 Android 开发要做的就是根据服务器返回的错误码告诉用户这里出了什么错误。
为什么要使用 token
一般情况下,客户端都需要向服务端获取数据和上传数据,那么服务器就需要知道具体的每一个请求是由哪一个用户发起的,服务端才好操作相对应用户的数据。在初始阶段是通过每次请求都带上用户名和密码来唯一确认一个请求的,但是这样会使服务器的压力增大,会增加服务器的查询操作。因此 token 应运而生,在每次登录成功之后,都保存服务端生成的唯一 token 到本地,就可以唯一确认一个请求了,我们就可以顺畅地访问服务端了。说了那么多,我们用图来捋一捋:
这里写图片描述
在 Android 中应该如何使用 token
一般情况下,有一下两种方式携带 token:
- 可以直接在每一个 get/post 请求的参数中加上 token;
- 可以在请求头中加上 token 参数;
不过选用哪一种方式,都是需要跟后端人员协商的。这么说来,每 一次请求都需要携带 token,每次的操作都是一样的,那有没有什么一劳永逸的办法?这就衍生出一个新的问题:全局处理 token
Android 中全局处理 token
这个是通过 okhttp+retrofit 实现的,通过拦截器拦截请求,再往请求头里面添加 token。那么具体的实现是这样的:(代码中有注释,这里就不过多解释了)
需要使用到的库:
compile 'com.squareup.okhttp3:okhttp:3.0.1'
compile 'com.squareup.okhttp3:logging-interceptor:3.0.1'
compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'
public class RetrofitServiceInstance {
private static RetrofitService instance = null;
public static RetrofitService getInstance() {
Authenticator authenticator = new Authenticator() {//当服务器返回的状态码为401时,会自动执行里面的代码,也就实现了自动刷新token
@Override
public Request authenticate(Route route, Response response) throws IOException {
L.d("==========> 重新刷新了token");//这里可以进行刷新 token 的操作
// instance.getUploadToken()
return response.request().newBuilder()
.addHeader("token", "")
.build();
}
};
Interceptor tokenInterceptor = new Interceptor() {//全局拦截器,往请求头部添加 token 字段,实现了全局添加 token
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();//获取请求
Request tokenRequest = null;
if (TextUtils.isEmpty(MyApplication.getToken())) {//对 token 进行判空,如果为空,则不进行修改
return chain.proceed(originalRequest);
}
tokenRequest = originalRequest.newBuilder()//往请求头中添加 token 字段
.header("token", MyApplication.getToken())
.build();
return chain.proceed(tokenRequest);
}
};
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {//log拦截器,打印所有的log
@Override
public void log(String message) {
L.d(message);
}
});
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.addNetworkInterceptor(tokenInterceptor)
.addInterceptor(loggingInterceptor)//使用上面的拦截器
.authenticator(authenticator)
.build();
if (instance == null) {
synchronized (RetrofitService.class) {
if (instance == null) {
Retrofit retrofit = new Retrofit.Builder() //生成实例
.baseUrl(CommenPara.serverURL) //基础url,会拼接NetService中的参数
.client(client) //使用 okhttp
.addConverterFactory(GsonConverterFactory.create()) //使用Gson解析
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) //加入RxJava的适配器
.build();
instance = retrofit.create(RetrofitService.class);
}
}
}
return instance;
}
}