我我的理解:Cookie其實就是記錄用戶的一些信息、狀態行爲等。有這樣一種場景,用戶在登陸成功後,服務端會返回Cookie,裏面包含用戶的登錄狀態信息等,這樣用戶在訪問本身的收藏列表時,加上這個Cookie,那麼就可直接獲取到文章列表,若是沒有Cookie,那服務端怎麼知道你是要獲取哪一個用戶的文章列表呢。java
在瀏覽器上,返回的Cookie會保存在瀏覽器中,在下次訪問時會自動加上該段Cookie,而Android端,須要咱們本身來保存服務端返回的Cookie,並在下次訪問的時候本身添加上。至於如何保存(Cookie持久化),方法不少,能夠用數據庫、文件、SharedPreferences、也可使用Webview的CookieManager。android
你們能夠看這篇文章Cookie介紹及在Android中的使用總結超詳細,看這一篇就夠了git
Cookie訪問時添加上其實就是使用header來添加頭部信息,至於怎麼添加上篇文章已經介紹,但顯然不能這樣,總不能在每一個須要Cookie的api上都寫上頭部信息或動態添加,那這樣也太繁瑣了,接下來咱們將經過攔截器來動態添加。github
本篇文章我將採用Wandroid網站中的登錄接口和收藏文章列表接口數據庫
登錄json
https://www.wanandroid.com/user/login
方法:POST
參數:
username,password
複製代碼
登陸後會在cookie中返回帳號密碼,只要在客戶端作cookie持久化存儲便可自動登陸驗證。api
收藏文章列表瀏覽器
https://www.wanandroid.com/lg/collect/list/0/json
方法:GET
參數: 頁碼:拼接在連接中,從0開始。
複製代碼
在網站上登陸後,能夠直接訪問www.wanandroid.com/lg/collect/…查看本身收藏的文章。服務器
你們能夠如今該網站上註冊個帳號而且收藏幾篇文章,供下面使用。cookie
爲何要說OkHttp呢,由於Retrofit底層就是使用OkHttp實現的,只是對其進行了封裝,咱們能夠經過Okhttp中的Interceptor攔截器來設置請求頭,而後經過retrofit.client(okhttpclient)對請求頭進行修改,這樣就省去了咱們手動添加請求頭的步驟。
這裏咱們建立兩個攔截器,一個用於登陸時接收Cookie保存在本地,另外一個攔截器用於訪問時在請求裏添加Cookie。
public class ReceivedCookiesInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
//攔截的cookie保存在originalResponse中
Response originalResponse = chain.proceed(chain.request());
//打印cookie信息
Log.i(TAG, "intercept: "+ originalResponse.headers("Set-Cookie").toString());
...
return originalResponse;
}
}
複製代碼
經過chain.proceed(chain.request())
獲取到的response內保存了攔截到的cookie信息。
經過Log.i(TAG, "intercept: "+ originalResponse.headers("Set-Cookie").toString());
打印頭部信息日誌
咱們能夠看到網絡請求返回的cookie信息,咱們要作的就是將這個cookie保存在本地。
這裏我將採用sharepreference的方式來存儲Cookie
先判斷Set-Cookie的頭部不爲空
if (!originalResponse.headers("Set-Cookie").isEmpty()) {
...
}
複製代碼
經過循環將Cookie信息放入到HashSet集合中
HashSet<String> cookies = new HashSet<>();
for(String header: originalResponse.headers("Set-Cookie"))
{
cookies.add(header);
}
複製代碼
經過SharePreference將Cookie信息保存在本地
//保存的sharepreference文件名爲cookieData
SharedPreferences sharedPreferences = context.getSharedPreferences("cookieData", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putStringSet("cookie", cookies);
editor.commit();
複製代碼
public class ReceivedCookiesInterceptor implements Interceptor {
public ReceivedCookiesInterceptor() {
super();
}
@Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
//這裏獲取請求返回的cookie
if (!originalResponse.headers("Set-Cookie").isEmpty()) {
HashSet<String> cookies = new HashSet<>();
for(String header: originalResponse.headers("Set-Cookie"))
{
LogUtil.i(TAG, "攔截的cookie是:"+header);
cookies.add(header);
}
//保存的sharepreference文件名爲cookieData
SharedPreferences sharedPreferences = App.getInstance().getSharedPreferences("cookieData", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putStringSet("cookie", cookies);
editor.commit();
}
return originalResponse;
}
}
複製代碼
public class AddCookiesInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
......
}
}
複製代碼
Request.Builder builder = chain.request().newBuilder();
HashSet<String> perferences = (HashSet) App.getInstance().getSharedPreferences("cookieData", Context.MODE_PRIVATE).getStringSet("cookie", null);
if (perferences != null) {
for (String cookie : perferences) {
builder.addHeader("Cookie", cookie);
}
}
return chain.proceed(builder.build());
複製代碼
public class AddCookiesInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request.Builder builder = chain.request().newBuilder();
HashSet<String> perferences = (HashSet) App.getInstance().getSharedPreferences("cookieData", Context.MODE_PRIVATE).getStringSet("cookie", null);
if (perferences != null) {
for (String cookie : perferences) {
builder.addHeader("Cookie", cookie);
}
}
return chain.proceed(builder.build());
}
}
複製代碼
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new ReceivedCookiesInterceptor())
.build();
複製代碼
private Retrofit retrofitLogin;
retrofitLogin = new Retrofit.Builder()
.baseUrl("https://a/")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
複製代碼
public interface Api {
//登陸接口
@FormUrlEncoded
@POST
Call<UserBean> login(@Url String url, @FieldMap Map<String, String> param);
}
複製代碼
private Api loginApi;
loginApi = retrofitLogin.create(Api.class);
複製代碼
Map<String, String> param = new HashMap<>();
param.put("username", etUsername.getText().toString());
param.put("password", etPwd.getText().toString());
loginApi.login(loginUrl, param).enqueue(new Callback<UserBean>() {
@Override
public void onResponse(Call<UserBean> call, Response<UserBean> response) {
if (response != null && response.body() != null) {
if (response.body().getErrorCode() == 0) {
Toast.makeText(getApplicationContext(), "登陸成功", Toast.LENGTH_SHORT).show();}
else {
Toast.makeText(getApplicationContext(), "登陸失敗" + response.body().getErrorCode() + response.body().getErrorMsg(), Toast.LENGTH_SHORT).show();
}
}
}
@Override
public void onFailure(Call<UserBean> call, Throwable t) {
Toast.makeText(getApplicationContext(), "登陸失敗"+t, Toast.LENGTH_SHORT).show();
}
});
}
else {
Toast.makeText(this, "請輸入完整的用戶信息", Toast.LENGTH_SHORT).show();
}
複製代碼
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new AddCookiesInterceptor())
.build();
複製代碼
retrofitCollect = new Retrofit.Builder()
.baseUrl("https://www.wanandroid.com/")
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
複製代碼
public interface Api {
//獲取收藏列表
@GET("lg/collect/list/{page}/json")
Call<MyCollectionBean> getCollecEssay(@Path("page") int page);
}
複製代碼
private Retrofit retrofitCollect;
private Api getCollectApi;
getCollectApi = retrofitCollect.create(Api.class);
複製代碼
getCollectApi.getCollecEssay(0).enqueue(new Callback<MyCollectionBean>() {
@Override
public void onResponse(Call<MyCollectionBean> call, Response<MyCollectionBean> response) {
if (response != null && response.body() != null) {
if (response.body().getErrorCode() == 0) {
Log.i(TAG, "onResponse: 獲取文章列表成功");
for (int i = 0; i < response.body().getData().getDatas().size(); i++) {
Log.i(TAG, "\n 收藏的標題名爲:" + response.body().getData().getDatas().get(i).getTitle());
}
} else {
Log.i(TAG, "onResponse: 獲取文章列表失敗"+response.body().getErrorMsg());
}
}
}
@Override
public void onFailure(Call<MyCollectionBean> call, Throwable t) {
Log.i(TAG, "onResponse: 獲取文章列表失敗"+t);
}
});
複製代碼
以上就是所有內容,具體代碼見Github。
其實咱們使用攔截器的目的就是爲了將Cookie信息攔截保存到本地和經過攔截器將Cookie添加到頭部信息裏,是爲了簡化咱們手動去添加頭部信息這一步。
以上就是所有內容,若是有錯誤的地方還望指出,對你有幫助的話麻煩看官給個start唄。關於Retrofit的圖片上傳文章還在編輯中,至於怎麼用雲服務器給你們寫個圖片上傳接口,還在想怎麼搞,後臺小白一枚,會的大佬麻煩指導指導我。