okhttp框架的使用

来源:互联网 发布:同济大学图书馆知乎 编辑:程序博客网 时间:2024/05/17 02:59

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 */

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

0 0
原创粉丝点击