okhttp框架的使用

39 篇文章 0 订阅

okHttp框架

OKHttp是一款高效的HTTP客户端,支持连接同一地址的链接共享同一个socket,
通过连接池来减小响应延迟,还有透明的GZIP压缩,请求缓存等优势

jar包依赖

需要添加两个jar包okhttp和对应版本的okio

本文使用okhttp3.3 okio1.6

GET 方式

建立连接

Request对象用于建立连接

// 首先得有一个OkHttpClient对象
OkHttpClient mOkClient = new OkHttpClient();
// 创建请求对象
Request request = new Builder().url(URL_STR).build();

接收请求

Reponse对象用于接收响应

Response response = mOkClient.newCall(request).execute();

以同步的方式接收请求,会产生阻塞

public class Main {
    private static OkHttpClient mOkClient = new OkHttpClient();

    private final static String URL_STR = "https://www.baidu.com";

    public static void main(String[] args) {
        // 创建请求对象
        Request request = new Builder().url(URL_STR).build();
        try {
            // 创建回调并执行响应    
            Response response = mOkClient.newCall(request).execute();
            if (response.isSuccessful()) {
                System.out.println(response.body().string());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

异步执行

通过request的对象去构造得到一个Call对象,类似于将你的请求封装成了任务,既然是任务,就会有execute()和cancel()等方法。
将call加入调度队列,然后等待任务执行完成,我们在Callback中即可得到结果。

public class Main {
    private static OkHttpClient mOkClient = new OkHttpClient();

    private final static String URL_STR = "https://www.baidu.com";

    public static void main(String[] args) {
        // 创建请求对象
        Request request = new Builder().url(URL_STR).build();
        // 创建回调对象,用于请求后的回调
        Call call = mOkClient.newCall(request);
        call.enqueue(new Callback() {

            // 收到响应时回调         
            @Override
            public void onResponse(Call call, Response reponse) throws IOException {
                String htmlBody = reponse.body().string();
                System.out.println(htmlBody);

            }
            // 没有收到响应时回调,响应失败
            @Override
            public void onFailure(Call arg0, IOException arg1) {

            }
        });
    }
}
通过response.string(),以字符串的形式 描述响应,response.bytes()以字节数组的形式描述响应
,response.inputstream(),获取该响应的输入流(支持大文件的读取)
如果响应体超过1MB,应该使用流进行存取(string会将文件加载到内存中)

输出结果(两种执行方式均相同)

<html>
<head>
    <script>
        location.replace(location.href.replace("https://","http://"));
    </script>
</head>
<body>
    <noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>
</body>
</html>

POST 方式,携带参数

构建POST请求

Request request = new Request.Builder() 
.url("https://www.baidu.com") 
.header("User-Agent", "OkHttp Headers.java") 
.addHeader("Accept", "application/json; q=0.5") 
.addHeader("Accept", "application/vnd.github.v3+json") 
.build(); 
此处除了构造request对象略有不同之外,其他与GET请求均相同
public class Main2 {
    private static OkHttpClient mOkHttpClient = new OkHttpClient();
    private static String URL = "https://www.baidu.com";

    public static void main(String[] args) {
        // 构造post参数 okhttp3.x中的方法
        FormBody body = new FormBody.Builder().add("key", "value").build();
        Request request = new Request.Builder().url(URL).build();
        // 其他与GET请求相同,这里仅用同步方式测试
        try {
            Response response = mOkHttpClient.newCall(request).execute();
            if (response.isSuccessful()) {
                System.out.println(response.code());
                System.out.println(response.body().string());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
打印响应头
// 打印响应头
Headers headers = response.headers();
for (int i = 0; i < headers.size(); i++) {
    System.out.println(headers.name(i) + " : " + headers.value(i));
}


/*
    Server : nginx/1.4.6 (Ubuntu)
    Date : Fri, 27 May 2016 01:43:43 GMT
    Content-Type : text/plain
    Content-Length : 1759
    Last-Modified : Tue, 27 May 2014 02:35:47 GMT
    Connection : keep-alive
    ETag : "5383fa03-6df"
    Accept-Ranges : bytes
*/

响应缓存

为了缓存响应,你需要一个你可以读写的缓存目录,和缓存大小的限制。这个缓存目录应该是私有的,不信任的程序应不能读取缓存内容。
一个缓存目录同时拥有多个缓存访问是错误的。大多数程序只需要调用一次new OkHttp(),在第一次调用时配置好缓存,
然后其他地方只需要调用这个实例就可以了。否则两个缓存示例互相干扰,破坏响应缓存,而且有可能会导致程序崩溃。
响应缓存使用HTTP头作为配置。你可以在请求头中添加Cache-Control: max-stale=3600 ,OkHttp缓存会支持。
你的服务通过响应头确定响应缓存多长时间,例如使用Cache-Control: max-age=9600。

public class Main3 {
    // 设置缓存目录
    private static File CACHE_DIR = new File("./cache");

    public static void main(String[] args) {
        int cacheSize = 1024 * 1024 * 10; // 1MB
        // 创建Okhttpclient对象
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        // 创建缓存  注意okhttp3.3创建缓存的方法和2.X版本有很大不同,需在Okhttpclient对象中创建
        Cache cache = new Cache(CACHE_DIR, cacheSize);
        builder.cache(cache);
        OkHttpClient client = builder.build();
        // 使用新线程开始请求
        new Thread() {
            public void run() {
                try {
                    execute(client);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            };
        }.start();

    }


    /**
     *  使用requset建立请求
     */
    public static void execute(OkHttpClient client) throws Exception {
        Request request = new Request.Builder().url("http://publicobject.com/helloworld.txt").build();

        Response response1 = client.newCall(request).execute();
        if (!response1.isSuccessful())
            throw new IOException("Unexpected code " + response1);

        String response1Body = response1.body().string();
        System.out.println("Response 1 response:          " + response1);
        System.out.println("Response 1 cache response:    " + response1.cacheResponse());
        System.out.println("Response 1 network response:  " + response1.networkResponse());

        request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();

        // 再次建立请求
        Response response2 = client.newCall(request).execute();
        if (!response2.isSuccessful())
            throw new IOException("Unexpected code " + response2);

        String response2Body = response2.body().string();
        System.out.println("Response 2 response:          " + response2);
        System.out.println("Response 2 cache response:    " + response2.cacheResponse());
        System.out.println("Response 2 network response:  " + response2.networkResponse());

        // 如果为同一个对象,则缓存有效 
        System.out.println("Response 2 equals Response 1? " + response1Body.equals(response2Body));

    }
}

/*
    结果:
    Response 1 response:          Response{protocol=http/1.1, code=200, message=OK, url=https://publicobject.com/helloworld.txt}
    Response 1 cache response:    null
    Response 1 network response:  Response{protocol=http/1.1, code=200, message=OK, url=https://publicobject.com/helloworld.txt}
    Response 2 response:          Response{protocol=http/1.1, code=200, message=OK, url=https://publicobject.com/helloworld.txt}
    Response 2 cache response:    Response{protocol=http/1.1, code=200, message=OK, url=https://publicobject.com/helloworld.txt}
    Response 2 network response:  null
    Response 2 equals Response 1? true
 */
此结果表明,缓存被重用
缓存文件

这里写图片描述

取消操作

网络操作中,经常会使用到对请求的cancel操作,okhttp的也提供了这方面的接口,call的cancel操作。
使用Call.cancel()可以立即停止掉一个正在执行的call。如果一个线程正在写请求或者读响应,将会引发IOException,
同时可以通过Request.Builder.tag(Object tag)给请求设置一个标签,
并使用OkHttpClient.cancel(Object tag)来取消所有带有这个tag的call。
但如果该请求已经在做读写操作的时候,cancel是无法成功的,会抛出IOException异常。

public class Main4 {
    private static OkHttpClient client = new OkHttpClient();

    public static void main(String[] args) {
        // 这个Http请求会延时2秒
        Request request = new Request.Builder().url("http://httpbin.org/delay/2").build();
        Call call = client.newCall(request);
        long startTime = System.nanoTime(); // 系统当前时间戳

        // 在1秒的时候取消请求
        new Timer().schedule(new TimerTask() {

            @Override
            public void run() {
                System.out.printf("%.2f Canceling call.%n", (System.nanoTime() - startTime) / 1e9f);
                call.cancel();
                System.out.printf("%.2f Canceled call.%n", (System.nanoTime() - startTime) / 1e9f);
            }
            // 此处将关闭时间设置5秒左右(视网络情况而定),输出结果为关闭失败
            // 此处将关闭时间设置为2秒以内,输出为关闭成功,会捕获到 java.net.SocketException
        }, 2000); // second mills
        // 开始执行请求
        try {
            System.out.printf("%.2f Executing call.%n", (System.nanoTime() - startTime) / 1e9f);
            Response response = call.execute();
            System.out.printf("call is cancel:" + call.isCanceled() + "%n");
            System.out.printf("%.2f Call was expected to fail, but completed: %s%n",
                    (System.nanoTime() - startTime) / 1e9f, response);
        } catch (IOException e) {
            // 捕获到异常,表示取消请求
            System.out.printf("%.2f Call failed as expected: %s%n", (System.nanoTime() - startTime) / 1e9f, e);
        }
    }
}

// 设置参数不同,此时会有两种可能
/*
    关闭失败,此时已结束IO
    0.00 Executing call.
    call is cancel:false
    2.94 Call was expected to fail, but completed: 
    Response{protocol=http/1.1, code=200, message=OK, url=http://httpbin.org/delay/2}
    10.00 Canceling call.
    10.00 Canceled call.

 */



/*
    关闭成功,此时尚未接收响应
    0.00 Executing call.
    2.00 Canceling call.
    2.00 Canceled call.
    2.02 Call failed as expected: java.net.SocketException: Socket operation on nonsocket: configureBlocking

 */

基础的使用先介绍到这里,随后会介绍更复杂的用法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值