- 什麼是 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;
}
}