zoukankan      html  css  js  c++  java
  • Retrofit、Okhttp使用小记(cookie,accesstoken,POST

    博主在项目中用RxJava也差不多几个月了,但是结合Retrofit使用经验还不是太多。恰好新项目的后台是http+json的,就打算尝试一把。
    刚开始由于Retrofit还不太熟,但是后台接口急着测试,所以只好先用okhttp把接口测试成功先。
    最最简单的测试方法就是http在线测试啦,相信很多小伙伴都知道啦,不过还是给不知道的小伙伴科普一下吧,http://www.atool.org/httptest.php/

    okhttp比较简单,测试登录很快就测试成功了,但是在测试其他获取数据的接口时,遇到了一点小麻烦,因为后台做了cookie验证,需要保存登录时的cookie和登录接口返回的accesstoken才能成功获取到数据。
    至于保存cookie这个比较简单,都是借鉴一下前人的经验哈,把第一次请求的cookie信息保存到内存中,之后每次请求都使用相同的cookie请求就可以了。
    注意在junit测试的时候如果是异步,还没等到获取网络数据,测试就结束了,此时我们要在最后加上一句代码,让程序等待获取数据,不直接结束。
    System.in.read();
    先贴一下使用ok实现登录的代码:

    public Call UserLogin(String username, String pwd) {
            MemoryCookieStore cookieStore = new MemoryCookieStore();
            cookieJar = new CookieJarImpl(cookieStore);
            OkHttpClient client = new OkHttpClient.Builder()
                    .cookieJar(cookieJar)
                    .build();
    
            FormBody formBody = new FormBody.Builder()
                    .add("KEY", MD5.hexdigest("一个固定的key"))
                    .add("Action","接口名称")
                    .add("UserName", MyEncode.encode(username))
                    .add("PassWord", MyEncode.encode(pwd))
                    .build();
    
            Request request = new Request.Builder()
                    .url("baseURL:如:http://www.baidu.com/json/Userservice.ashx")
                    .post(formBody)
                    .build();
            Call call = client.newCall(request);
            return call;
        }

    其他的就不多说了,就是post的基本使用。
    重点是这两句代码:

    MemoryCookieStore cookieStore = new MemoryCookieStore();
    cookieJar = new CookieJarImpl(cookieStore);

    创建一个Cookie仓库,接着创建一个cookieJar、在okhttpClient中吧cookieJar设置进去即可。
    以上代码用到三个java类,
    CookieStore.javaMemoryCookieStore.javaCookieJarImpl.java 都是直接复制过来用的,是鸿洋封装的okhttpUtils里面的代码~

    之后每次访问后台接口都使用相同的cookieJar。

    使用okhttp测试接口比较简单,很快就测试好了。但是每次测试都要写一大堆东西,非常麻烦。
    再加上本来就是想要熟练一下Retrofit的使用的,之前只用在WebService上,很多使用都不一样,要注意的也不一样。
    接下来我们开始改造:
    如果接触过一点Retrofit的应该都知道要先写一个IApi接口吧。接口我们都知道,面向接口编程,达到解耦程序的目的。
    我们先新建一个IUserApi ,并添加一个登陆方法。

    public interface IUserApi {
        @POST("UserService.ashx")
        Observable<RequestResult<String>> login(
        @Query("Action") String action,
        @Query("KEY") String key,
        @Query("UserName") String username,
        @Query("PassWord") String password);
    }

    看上去应该没啥问题,基本上都是参考网上写的。
    接下来是使用。

    Retrofit retrofit = new Retrofit.Builder()
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())             
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(new MyOkHttpClient())
                    .baseUrl(Dic.BASEURL)
                    .build();
    IUserApi api = retrofit.create(IUserApi.class);
    api.login("login","key","fancy","123456")
       .subscribe(new ServerSubscriber<String>(iview) {
                        @Override
                        public void onMyNext(String accesstoken) {
                        System.out.println(accesstoken);
                    });

    在junit中测试时,不用加,加了会报错,正式使用的时候可以加上。

    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())

    接下来就是跑junit测试,哎,咋就是登陆失败呢。
    看上去明明和okhttp一样啊,用的okhttpClient就是之前的,怎么会有问题呢? 改了半天也没改出什么名堂来~最后决定使出我的终极绝招,HttpLoggingInterceptor http请求拦截,看看请求过程中有什么不一样。
    以下是okhttp方式的日志:

    信息:
    POST http://www.baidu.com/json/UserService.ashx http/1.1
    信息:
    KEY=1234353464565&Action=login&UserName=MKs6XgGG7ZJdKMqHI8sYSA%3D%3D%0A&PassWord=cAL%2BvRqMtRI%3D%0A

    一下是Retrofit方式的日志:

    信息:
     --> POST http://www.baidu.com/json/UserService.ashx?Action=userLogin&KEY=1234353464565&UserName=MKs6XgGG7ZJdKMqHI8sYSA%3D%3D%0A&PassWord=cAL%2BvRqMtRI%3D%0A http/1.1

    应该一眼就能看出区别了,前者是post到baseurl,参数是表单形式传递的。 而后者是直接连参数一起post过去了。

    那我们应该如何修改呢。最开始我也只是随便尝试,修改@Query,试试别的参数,查看了一下@Field(按住ctrl单击跳到对应类),对应的解释是Named pair for a form-encoded request.,感觉应该是这个。
    然后把请求接口中的@Query全都替换成了@Field。
    又跑了一遍,结果提示必须添加编码,这时候也不知道该如何添加编码,最后就直接百度了。其实只要再接口上添加一个@FormUrlEncoded 注解就可以了。
    最终的接口如下:

        @FormUrlEncoded
        @POST("UserService.ashx")
        Observable<RequestResult<String>> UserLogin(
                @Field("Action") String action,
                @Field("KEY") String key,
                @Field("UserName") String username,
                @Field("PassWord") String password);

    再跑一遍就能够登录成功了。
    关于获取数据,测试前需要先登录,然后使用相同的cookie和登录的accesstoken才能够成功获取到数据。

    这个就要rxjava来配合了,当然你也可以用okhttp迷之缩进哈,至于代码的可读性和通用性,那就不好说了,谁用谁知道是不?
    Retrofit本来就提供了rxjava支持的,所以我们用rxjava来实现线程调度~ !!! 拒绝迷之缩进 !!!
    因为Retrofit的创建基本是通用的,就直接封到一个RetrofitUtil.create()方法里面了。

    Retrofit retrofit = RetrofitUtil.create("");
            IUserApi api = retrofit.create(IUserApi.class);
            TestApi.getAccesstoken()
                    .flatMap(new Func1<RequestResult<String>, Observable<? extends String>>() {
                        @Override
                        public Observable<? extends String> call(RequestResult<String> stringRequestResult) {
                            return api.getInfo("GetInfo", Dic.key, stringRequestResult.getAccesstoken());
                        }
                    })
                    .subscribe(new ServerSubscriber<String>() {
                        @Override
                        public void onNext(String s) {
                            System.out.println(s);
                        }
                    });

    一个flatMap就解决问题啦,是不是非常简单,用lambda格式化一下,会更加简洁。

    TestApi.getAccesstoken()
                    .flatMap(stringRequestResult -> api.getInfo("GetInfo", Dic.key, stringRequestResult.getAccesstoken()))
                    .subscribe(new ServerSubscriber<String>() {
                        @Override
                        public void onNext(String s) {
                            System.out.println(s);
                        }
                    });

    经过以上步骤基本上把okhttp改造成了Retrofit+Rx了。虽然暂时还看不出多大的优势,似乎只有在最后测试时获取token再获取数据那里稍微简单一点,但是,在正式使用的时候token不是第一次请求就保存下来了么,这种形式应该用不上吧。
    没错,在以上场景只是测试方便,在正式使用的时候并用不上。
    但是接下来的需求,RxJava应该能够让你心服口服。

    有点累,下篇博客再更吧。

  • 相关阅读:
    LeetCode 121. Best Time to Buy and Sell Stock
    LeetCode 221. Maximal Square
    LeetCode 152. Maximum Product Subarray
    LeetCode 53. Maximum Subarray
    LeetCode 91. Decode Ways
    LeetCode 64. Minimum Path Sum
    LeetCode 264. Ugly Number II
    LeetCode 263. Ugly Number
    LeetCode 50. Pow(x, n)
    LeetCode 279. Perfect Squares
  • 原文地址:https://www.cnblogs.com/onetwo/p/7278106.html
Copyright © 2011-2022 走看看