美文网首页Android
Okhttp 使用(同步、异步/get、post/上传文件)

Okhttp 使用(同步、异步/get、post/上传文件)

作者: 柬埔没有寨 | 来源:发表于2020-01-20 11:16 被阅读0次

    简介

    目前Android端调用网络请求最常用的框架就是OKHttp,目前项目中也经常会用到。OKHTTP有哪些特点呢?下面是官网给出的OKHTTP的特点:

    1. 支持HTTP/2, HTTP/2通过使用多路复用技术在一个单独的TCP连接上支持并发, 通过在一个连接上一次性发送多个请求来发送或接收数据;
    2. 如果HTTP/2不可用, 连接池复用技术也可以极大减少延时;
    3. 透明的Gzip处理降低了通信数据的大小
    4. 响应缓存完全避免了网络中的重复请求
    5. 使用Okio来简化数据的访问与存储,提高性能
    6. 如果您的服务器配置了多个IP地址, 当第一个IP连接失败的时候, OkHttp会自动尝试下一个IP
    7. OkHttp还处理了代理服务器问题和SSL握手失败问题;

    官网地址:https://square.github.io/okhttp/
    想要详细了解HTTP/2,可以参考:https://www.jianshu.com/p/828a29bced9f

    配置

    1. 添加OKHttp依赖
    implementation 'com.squareup.okhttp3:okhttp:3.12.3'
    
    1. 添加网络权限,如果需要文件读写文件读写权限
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    

    接下来就可以愉快的开始使用OKhttp进行开发了。

    创建OkHttpClient

    OKhttpclient通过builder构建,构建的时候涉及到很多配置项,本次简单对其中一些配置项做了说明,后续会对一些重要的配置项做专题说明。在实际的项目中的配置项根据项目具体需求进行配置。

        OkHttpClient.Builder builder = new OkHttpClient.Builder();
    
        //缓存目录
        File externalCacheDir = context.getExternalCacheDir();
        if (externalCacheDir != null) {
            Cache okHttpCache = new Cache(new File(externalCacheDir,
                    "HttpCache"), 30 * 1024 * 1024);
            builder.cache(okHttpCache);
        }
    
        //连接超时时间,连接超时是在将TCP SOCKET 连接到目标主机时应用的,默认10s
        builder.connectTimeout(30, TimeUnit.SECONDS);
        //读取超时时间, 包括TCP SOCKET和Source 和Response的读取IO操作,默认10s
        builder.readTimeout(20, TimeUnit.SECONDS);
        //写入超时时间,主要指IO的写入操作,默认10s
        builder.writeTimeout(20, TimeUnit.SECONDS);
        //整个调用时期的超时时间,包括解析DNS、链接、写入请求体、服务端处理、以及读取响应结果
        builder.callTimeout(120, TimeUnit.SECONDS);
    
        //用于单个client监听所有解析事件的,可以用于解析耗时计算
        builder.eventListener(EventListener.NONE);
    
        //添加拦截器,框架内部已经默认添加了部分拦截器,通过接口添加的拦截器在列表首部
        builder.addInterceptor(new LogInterceptor());
        //添加网络拦截器,网络拦截器可以操作重定向和失败重连的返回值,以及监控所有的网络数据
        builder.addNetworkInterceptor(new NetworkInterceptor());
    
        //在握手期间,如果URL的主机名和服务器的标识主机名不匹配,验证机制可以回调此接口的实现者,以确定是否应该允许此连接。
        //返回false表示不允许此链接,无脑return true 十分不安全
        builder.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });
    
    //授权,默认为Authenticator.NONE
    //        builder.authenticator(Authenticator.NONE);
    
    //连接池,默认5个空闲连接,连接保活5分钟
    //        builder.connectionPool(new ConnectionPool());
    
    //自定义CookieJar,默认CookieJar.NO_COOKIES
    //        builder.cookieJar(CookieJar.NO_COOKIES);
    
    //调度策略,默认最大并发数默认为 64,但个域名最大请求数 默认为 5 个
    //        builder.dispatcher(new Dispatcher());
    
    //配置证书认证策略
    //        builder.sslSocketFactory();
    
          OkHttpClient  client = builder.build();
    

    上述配置项中比较常用的有

    1. 缓存文件路径以及缓存的容量大小
    2. 网络请求的链接、读取、写入的超时时间
    3. 拦截器,这个是OKHTTP最常用的,可以用于处理包括重试、缓存、日志打印等功能
    4. 域名和证书的校验
    5. 连接器以及并发的调度策略等

    同步get请求

    public void synGet(String url) {
            
            // 第一步,构建HttpUrl
            HttpUrl.Builder builder = null;
            try {
                HttpUrl httpUrl = HttpUrl.parse(url);
                if(httpUrl != null){
                    builder = httpUrl.newBuilder();
                }
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            }
    
            if (builder == null) {
                return;
            }
            builder.addQueryParameter("key","value");
    
            // 第二步,构建Request请求对象
            Request request = new Request.Builder()
                    //请求地址
                    .url(httpUrl)
                    //get请求,默认为get请求
                    .get()
                    //添加请求头,一个key对应多个value,可以自定义
                    .addHeader("key", "value")
                    .addHeader("key", "value1")
                    //请求头,一对一的,如常见的Content-Type、Accept-Encoding等
                    .header("key1", "value1")
                    //缓存策略,当前使用强制网络请求
                    .cacheControl(CacheControl.FORCE_NETWORK)
                    //缓存策略
                    .build();
    
            try {
                //第三步,开始进行同步请求
                Response response = client
                        .newCall(request)
                        .execute();
    
                //第四步,解析响应结果
                ResponseBody body = response.body();
                if (body != null) {
                    Log.d(TAG, body.string());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    

    同步get请求会阻塞当前线程直到返回结果,请求大致分为四个步骤:

    1. 构建HttpUrl,当然这一步不是必须的,也可以直接传入地址
    2. 第二步,构建Request请求对象,可以设置请求头,缓存策略,请求方式
    3. 第三步,开始进行同步请求
    4. 解析响应结果

    注意:同步get请求要在子线程中进行,否应用会抛异常。

    异步get请求

    异步请求方式的步骤和上述前两个步骤基本一致,主要发起请求的方式发生了变化,结果通过回调返回。这种请求方式对请求的线程没有限制。

    
    // 第一步,构建HttpUrl
    // 第二步,构建Request请求对象
    //第三步,开始进行异步请求
    client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
    
                }
    
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    //第四步,解析响应结果
                    ResponseBody body = response.body();
                    if (body != null) {
                        Log.d(TAG, body.string());
                    }
                }
            });
    

    同步post请求

    public void synPost(String url) {
        // 第一步,构建HttpUrl
        HttpUrl.Builder builder = null;
        try {
            HttpUrl httpUrl = HttpUrl.parse(url);
            if (httpUrl != null) {
                builder = httpUrl.newBuilder();
            }
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
        if (builder == null) {
            return;
        }
    
        //第二步,构建RequestBody
        MediaType mediaType = MediaType.parse("application/json;charset=UTF-8");
        JSONObject jsonObject = new JSONObject();
        try {
            jsonObject.put("key1", "value1");
            jsonObject.put("key2", "value2");
        } catch (JSONException e) {
            e.printStackTrace();
        }
        RequestBody requestBody = RequestBody.create(mediaType, jsonObject.toString());
        // 第三步,构建Request请求对象
        Request request = new Request.Builder()
                .url(builder.build())
                .post(requestBody)
                .build();
        
        //第四步,开始进行同步post请求
        try {
            Response response = client.newCall(request).execute();
            //第五步,解析请求结果
            ResponseBody body = response.body();
            if (body != null) {
                Log.d(TAG, body.string());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    

    与get请求方式不同的是post请求需要构建RequestBody,在请求时携带RequestBody。

    异步post请求

    public void asynPost(String url) {
            // 第一步,构建HttpUrl
            //第二步,构建RequestBody
            // 第三步,构建Request请求对象
            Request request = new Request.Builder()
                    .url(builder.build())
                    .post(requestBody)
                    .build();
    
            client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    
                }
    
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    ResponseBody body = response.body();
                    if (body != null) {
                        Log.d(TAG, body.string());
                    }
                }
            });
        }
    

    上传文件

        //第一步,构建HttpUrl
        //第二步,构建RequestBody
        MediaType mediaType = MediaType.parse("multipart/form-data; charset=utf-8");
        RequestBody requestBody = RequestBody.create(mediaType, file);
        //第三步,构建MultipartBody
        MultipartBody body = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                //在此处添加多个requestBody实现多文件上传
                .addFormDataPart("file", file.getName(), requestBody)
                .build();
    
        // 第四步,构建Request请求对象
        Request request = new Request.Builder()
                .url(builder.build())
                .post(body)
                .build();
        // 第五步,构建Request请求对象
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
    
            }
    
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                ResponseBody body = response.body();
                if (body != null) {
                    Log.d(TAG, body.string());
                }
            }
        });
    

    表单提交

        //第二步,构建RequestBody
        FormBody formBody = new FormBody.Builder()
                .add("key1","value1")
                .add("key2","value2")
                .build();
    
        // 第三步,构建Request请求对象
        Request request = new Request.Builder()
                .url(builder.build())
                .post(formBody)
                .build();
    
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
    
            }
    
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                ResponseBody body = response.body();
                if (body != null) {
                    Log.d(TAG, body.string());
                }
            }
        });
    

    相关文章

      网友评论

        本文标题:Okhttp 使用(同步、异步/get、post/上传文件)

        本文链接:https://www.haomeiwen.com/subject/btljzctx.html