Retrofit——Cookie
2016-04-27 20:40
363 查看
今天学习了有关http的cookie知识后,刚好想结合retrofit来试验一下学习成果,于是拿了别人的接口来做实验。
要想获取cookie,那么肯定有个入口区提供cookie,一般都是在app应用的第一次访问时候(如登录或者登录前的验证),由服务器通过响应头来返回的,然后客户端获取到cookie后再以后的访问中加入header中进行访问。
fiddler抓包
用工具抓包,获取接口信息,大概信息如下:
http://[b]*****[/b]/updateToken
这个就是服务端返回的信息,cookie在响应头中,一般用浏览器抓包时,会发现访问接口的时候,在请求头中竟然会出现cookie的配置,那么它是从哪来的呢,别怕,这是因为你之前在该浏览器中已经访问过了,它做了记录,所以有了之前的cookie。解决如下:
1.删除浏览器的cookie(经测试,没有成功,估计姿势不对)
2.用手机模拟请求,并且抓包(就是用的这种)
好了,第一次请求的返回头已经有了,那么在retrofit该如何获取呢?
获取cookie
用retrofit当然得写拦截器,先贴上GetCookiesInterceptor代码
拦截器部分很简单,但是在做的过程中,因为本人项目中用的是Dagger架构,所以context得引入进来, 在Module中,提供实例
初始化配置
刚开始在考虑其他几个参数都可以在本类中提供,如http日志
但是Context如何取提供,后来查阅资料后,发现在AppModule中已经提供了上下文,只需要在写component时候引入进去,会自动调用,测试后发现没问题。
cookie的拦截器配置完毕,下面写Api以及调用方法。
Api调用
细心的读者会发现,方法的开始地方对sp进行了清空,目的就是避免之前存在内存中的cookie也会默认加到第一次访问的头中,这会导致访问无效,故清空。此处接口返回了token,则通过sp保存,再下次调用接口的时候获取调用即可。
http的拦截器是为了加cookie的头,第一次接口提供的头,你以后得用啊,下面贴http拦截器。
http拦截器
如果获取的cookie不为空,则表示不是第一次访问接口,加header的cookie,否则不加!
严重提醒:请注意服务器端提供的上传数据类型,笔者在上面吃过亏,用json上传传了很久都没成功,后来发现服务器只支持表单上传,醉了!cookie之所以长度-1,是之前获取的有“;”
第一次接口访问是为了获取cookie和token值,已经完成,都是准备工作,下面才是项目的正常访问。
正常的访问
注释部分即为json上传,吃了大亏咯。getGoods接口如下:
最后总结一下,其实真正的代码不难,难得是逻辑,得梳理请cookie和token的顺序以及调用关系,啥时获取cookie和token,啥时调用他们,好了,关于retrofit的cookie部分就讲到这里!
要想获取cookie,那么肯定有个入口区提供cookie,一般都是在app应用的第一次访问时候(如登录或者登录前的验证),由服务器通过响应头来返回的,然后客户端获取到cookie后再以后的访问中加入header中进行访问。
fiddler抓包
用工具抓包,获取接口信息,大概信息如下:
http://[b]*****[/b]/updateToken
这个就是服务端返回的信息,cookie在响应头中,一般用浏览器抓包时,会发现访问接口的时候,在请求头中竟然会出现cookie的配置,那么它是从哪来的呢,别怕,这是因为你之前在该浏览器中已经访问过了,它做了记录,所以有了之前的cookie。解决如下:
1.删除浏览器的cookie(经测试,没有成功,估计姿势不对)
2.用手机模拟请求,并且抓包(就是用的这种)
好了,第一次请求的返回头已经有了,那么在retrofit该如何获取呢?
获取cookie
用retrofit当然得写拦截器,先贴上GetCookiesInterceptor代码
public class GetCookiesInterceptor implements Interceptor { private Context context; public GetCookiesInterceptor(Context context) { super(); this.context = context; } @Override public Response intercept(Chain chain) throws IOException { Response originalResponse = chain.proceed(chain.request()); if (!originalResponse.headers("Set-Cookie").isEmpty()) { final StringBuffer cookieBuffer = new StringBuffer(); Observable.from(originalResponse.headers("Set-Cookie")) .map(new Func1<String, String>() { @Override public String call(String s) { String[] cookieArray = s.split(";"); return cookieArray[0]; } }) .subscribe(new Action1<String>() { @Override public void call(String cookie) { cookieBuffer.append(cookie).append(";"); } }); SharedPreferences sharedPreferences = context.getSharedPreferences("cookie", Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putString("cookie", cookieBuffer.toString()); editor.commit(); } return originalResponse; } }
拦截器部分很简单,但是在做的过程中,因为本人项目中用的是Dagger架构,所以context得引入进来, 在Module中,提供实例
初始化配置
@Provides @Singleton public OkHttpClient provideOkHttpClient(Context context,HttpLoggingInterceptor httpLoggingInterceptor, HttpInterceptor httpInterceptor/*, ProgressInterceptor progressInterceptor*/) { OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .writeTimeout(10, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .addInterceptor(httpLoggingInterceptor) .addInterceptor(new GetCookiesInterceptor(context)) .addInterceptor(httpInterceptor) return client; }
刚开始在考虑其他几个参数都可以在本类中提供,如http日志
@Provides @Singleton public HttpLoggingInterceptor provideHttpLoggingInterceptor() { HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); if (BuildConfig.DEBUG) { httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); } else { httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.NONE); } return httpLoggingInterceptor; }
但是Context如何取提供,后来查阅资料后,发现在AppModule中已经提供了上下文,只需要在写component时候引入进去,会自动调用,测试后发现没问题。
@Module public class AppModule { App application; public AppModule(App application) { this.application = application; } @Provides @Singleton public Context provideContext() { return application; } }
cookie的拦截器配置完毕,下面写Api以及调用方法。
Api调用
@POST("data/token/updateToken") Observable<TestHBC> getHBCToken();
private void getHBCToken() { SharedPreferences sharedPreferences1 = getSharedPreferences("cookie", Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences1.edit(); editor.putString("cookie", ""); editor.commit(); subscription1 = clientApi.getHBCToken() .compose(SchedulersCompat.<TestHBC>applyIoSchedulers()) .subscribe(new Subscriber<TestHBC>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { showToast("指数更新失败" + e.toString()); } @Override public void onNext(TestHBC testHBC) { testToken = testHBC.getToken(); SharedPreferences.Editor edit = sharedPreferences.edit(); edit.putString("token", testToken); edit.commit(); } }); mCompositeSubscription.add(subscription1); }
细心的读者会发现,方法的开始地方对sp进行了清空,目的就是避免之前存在内存中的cookie也会默认加到第一次访问的头中,这会导致访问无效,故清空。此处接口返回了token,则通过sp保存,再下次调用接口的时候获取调用即可。
http的拦截器是为了加cookie的头,第一次接口提供的头,你以后得用啊,下面贴http拦截器。
http拦截器
public Response intercept(Chain chain) throws IOException { SharedPreferences sharedPreferences = context.getSharedPreferences("cookie", Context.MODE_PRIVATE); String cookie = sharedPreferences.getString("cookie", ""); Request request = chain.request(); Response response; if (!cookie.equals("")) { Request compressedRequest = request.newBuilder() .header("Content-type","application/x-www-form-urlencoded; charset=UTF-8") .header("cookie", cookie.substring(0,cookie.length()-1)) .build(); response = chain.proceed(compressedRequest); }else{ response = chain.proceed(request); } return response; }
如果获取的cookie不为空,则表示不是第一次访问接口,加header的cookie,否则不加!
严重提醒:请注意服务器端提供的上传数据类型,笔者在上面吃过亏,用json上传传了很久都没成功,后来发现服务器只支持表单上传,醉了!cookie之所以长度-1,是之前获取的有“;”
第一次接口访问是为了获取cookie和token值,已经完成,都是准备工作,下面才是项目的正常访问。
正常的访问
private void getGoods() { String token = sharedPreferences.getString("token", ""); /* UpGetGoods upGetGoods = new UpGetGoods(); upGetGoods.setToken(token); upGetGoods.setOs("android");*/ subscription2 = clientApi.getGoods("android",token) .compose(SchedulersCompat.<TestGetGoods>applyIoSchedulers()) .subscribe(new Subscriber<TestGetGoods>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { showToast("指数更新失败" + e.toString()); } @Override public void onNext(TestGetGoods testHBC) { } }); mCompositeSubscription.add(subscription1); }
注释部分即为json上传,吃了大亏咯。getGoods接口如下:
@FormUrlEncoded @POST("data/store/getGoods") Observable<TestGetGoods> getGoods(@Field("os") String os,@Field("token") String token);
最后总结一下,其实真正的代码不难,难得是逻辑,得梳理请cookie和token的顺序以及调用关系,啥时获取cookie和token,啥时调用他们,好了,关于retrofit的cookie部分就讲到这里!
相关文章推荐
- cookie的secure属性详解
- 浏览器 cookie 限制
- extjs 为某个事件设置拦截器
- android读写cookie的方法示例
- 浅谈COOKIE和SESSION区别
- 深入解析Session是否必须依赖Cookie
- 对比分析php中Cookie与Session的异同
- 新手菜鸟必读:session与cookie的区别
- php实现通过cookie换肤的方法
- ASP.NET中Application、Cookie、Session、Cache和ViewState
- C#中Cookie之存储对象
- C#基于WebBrowser获取cookie的实现方法
- ASP.NET Cookie 操作实现
- php中cookie的作用域
- 写入cookie的JavaScript代码库 cookieLibrary.js
- 关于cookie的初识和运用(js和jq)
- JavaScript cookie 跨域访问之广告推广
- ie7下利用ajax跨域盗取cookie的解决办法
- JS使用cookie实现DIV提示框只显示一次的方法