美文网首页
okhttp封装,

okhttp封装,

作者: xqiiitan | 来源:发表于2025-08-24 16:57 被阅读0次

1.http协议:

核心差异快速概览

特性 HTTP/1.0 HTTP/1.1 HTTP/2
连接方式 短连接(非持久) 长连接(持久) 多路复用(持久)
TCP连接数 每个请求一个TCP连接 多个请求共享一个TCP连接 一个TCP连接并行处理无数请求
队头阻塞 严重(连接级别) 存在(请求级别) 几乎消除(协议级别)
服务器推送 不支持 不支持 支持
头部压缩 不支持 不支持 支持(HPACK)
数据格式 文本 文本 二进制分帧
主机头 非必需 必需(Host Header) 必需
缓存控制 Expires, Pragma Cache-Control, ETag 同HTTP/1.1

1.0 HTTP/1.0 (1996)

短连接(非持久连接),缓存功能较弱,主要依赖 Expires(过期时间)和 Last-Modified(最后修改时间)等头部。

1.1 HTTP/1.1 (1997)

长连接(持久连接),允许在同一个连接上发送多个请求和响应。通过 Connection: keep-alive 头部启用(现在已是默认行为)。这大大减少了TCP握手和慢启动的开销。
强大的缓存控制:引入了功能强大的 Cache-Control 头部,以及 ETag(实体标签)等验证器,提供了更精细的缓存策略。

1.2 HTTP/2 (2015)性能优化

二进制分帧:基础性改变。HTTP/2不再使用纯文本格式通信,而是将所有信息封装在二进制帧中。帧是传输的最小单位,这使得解析更高效、更快速,且错误更少。
多路复用:核心特性。
头部压缩,服务器推送

总结演进历程

版本1.0 → 1.1: 从短连接到长连接,大幅减少连接开销。 存在请求级队头阻塞,并发能力有限。
版本1.1 → 2 :
从文本、有序到二进制、多路复用,彻底解决队头阻塞,极大提升并发效率。引入头部压缩和服务器推送。
底层仍基于TCP,可能受到TCP级队头阻塞(如果有一个TCP包丢失,所有流都会等待重传)。
HTTP/2 在性能上相比 HTTP/1.1 是巨大的飞跃,尤其是在需要高并发请求的现代网页)中表现尤为出色。目前,绝大多数现代浏览器和主流网站都已支持HTTP/2。

2.okhttp优点:

实现了Http2.0; 支持通道复用性能开销小; 同一个域名多台主机会有重连重试机制,稳定性高; 能设置缓存。

3.封装的思想(分层的思想)(架构)

基于接口,做分层处理。

    implementation 'com.squareup.okhttp3:okhttp:4.11.0' // 使用最新版本
    implementation 'com.squareup.okhttp3:logging-interceptor:4.11.0' // 日志拦截器(可选)
    implementation 'com.google.code.gson:gson:2.3.1'

3.1 接口层 IRequest, IResponse, IHttpClient

// IRequest.java
package com.example.android1.mytaxi.common.http;
import java.util.Map;
/**
 * Created by  on 17/4/24.
 * 定义请求数据的封装方式
 */
public interface IRequest {
    public static final String POST = "POST";
    public static final String GET = "GET";

    /**
     * 指定请求方式
      */
    void setMethod(String method);

    /**
     * 指定请求头部
     * @param key
     * @param value
     */
    void setHeader(String key, String value);
    /**
     *  指定请求参数
     * @param key
     * @param value
     */
    void setBody(String key, String value);

    /**
     * 提供给执行库请求行URL
     * @return
     */
    String getUrl();
    /**
     * 提供给执行库请求头部
     * @return
     */
    Map<String, String> getHeader();
    /**
     * 提供给执行库请求参数
     * @return
     */
    Object getBody();
}
public interface IResponse {
    // 状态码
    int getCode();
    // 数据体
    String getData();
}
public interface IHttpClient {
    IResponse get(IRequest request, boolean forceCache);
    IResponse post(IRequest request, boolean forceCache);
}

3.2 http实现层。

package com.example.android1.mytaxi.common.http.biz;
/**
 * Created by liuguangli on 17/5/6.
 * 返回业务数据的公共格式
 */
public class BaseBizResponse {
    public static final int STATE_OK = 200;
    // 密码错误
    public static final int STATE_PW_ERR = 100005;
    // token 无效/过期
    public static final int STATE_TOKEN_INVALID = 100006;
    // 用户已经存在
    public static int STATE_USER_EXIST = 100003;
    // 用户不存在
    public static int STATE_USER_NOT_EXIST = 100002;
    // 状态码
    private int code;
    private String msg;

    public int getCode() {
        return code;
    }
    public void setCode(int code) {
        this.code = code;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
}
public class LoginResponse extends BaseBizResponse {
    Account data;
    public Account getData() {
        return data;
    }
    public void setData(Account data) {
        this.data = data;
    }
}

// BaseRequest.java

package com.example.android1.mytaxi.common.http.impl;



import com.example.android1.mytaxi.common.http.IRequest;
import com.example.android1.mytaxi.common.http.api.API;
import com.google.gson.Gson;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by liuguangli on 17/4/24.
 * 封装参数的实现
 */

public class BaseRequest implements IRequest {
    private String method = POST;
    private String url;
    private Map<String, String> header;
    private Map<String, Object> body;

    public BaseRequest(String url) {
        /**
         *  公共参数及头部信息,appId+appKey
         */
        this.url = url;
        header = new HashMap();
        body = new HashMap<>();
        header.put("X-Bmob-Application-Id", API.Config.getAppId());
        header.put("X-Bmob-REST-API-Key", API.Config.getAppKey());
    }

    @Override
    public void  setMethod(String method) {
       this.method = method;
    }
    public void setHeader(String key, String value) {
        header.put(key, value);
    }

    public void setBody(String key, String value) {
        body.put(key, value);
    }

    @Override
    public String getUrl() {
        if (GET.equals(method)) { //处理get方法的url.
            // 组装 Get 请求参数: 遍历所有key,获取对应的value 替换到占位符上。
            // 拼装成完整的url
            for (String key : body.keySet()) {
                url = url.replace("${" + key + "}", body.get(key).toString());
            }
        }
        return url;
    }

    @Override
    public Map<String, String> getHeader() {
        return header;
    }

    @Override
    public String getBody() {
        if (body != null) {
            // 组装 POST 方法请求参数
            return new Gson().toJson(this.body, HashMap.class);
        } else {
            return  "{}";
        }
    }
}

// BaseResponse.java

package com.example.android1.mytaxi.common.http.impl;
import com.example.android1.mytaxi.common.http.IResponse;

/**
 * Created by  on 17/4/24.
 */
public class BaseResponse implements IResponse {
    public static final int STATE_UNKNOWN_ERROR = 100001;
    public static final int STATE_OK = 200; //状态码

    // 状态码
    private int code;
    // 响应数据
    private String data;
    @Override
    public String getData() {
        return data;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public void setData(String data) {
        this.data = data;
    }
}

// OkHttpClientImpl.java

package com.example.android1.mytaxi.common.http.impl;

import android.util.Log;
import com.example.android1.mytaxi.common.http.IHttpClient;
import com.example.android1.mytaxi.common.http.IRequest;
import com.example.android1.mytaxi.common.http.IResponse;

import java.io.IOException;
import java.util.Map;

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * OkHttp 的是实现
 * Created by  on 17/4/24.
 */
public class OkHttpClientImpl implements IHttpClient {
    OkHttpClient mOkHttpClient = new OkHttpClient.Builder()
            .build();

    @Override
    public IResponse get(IRequest request, boolean force) {
        /**
         *  解析业务参数
         */
        // 指定请求方式 get
        request.setMethod(IRequest.GET);
        // 解析头部
        Map<String, String> header = request.getHeader();
        // OkHttp 的 Request.Builder
        Request.Builder builder = new Request.Builder();
        for (String key : header.keySet()) {
            // 组装成 OkHttp 的 Header
            builder.header(key, header.get(key));
        }
        // 获取 url
        String url = request.getUrl();
        builder.url(url).get();
        Request oKRequest = builder.build();
        // 执行 OkHttp的 Request
        return execute(oKRequest);
    }

    @Override
    public IResponse post(IRequest request, boolean foreCache) {
        // 指定请求方式 post.
        request.setMethod(IRequest.POST);
        MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
        RequestBody body = RequestBody.create(mediaType, request.getBody().toString());
        Map<String, String> header = request.getHeader();
        Request.Builder builder = new Request.Builder();
        for (String key : header.keySet()) {
            builder.header(key, header.get(key));
        }
        builder.url(request.getUrl()).post(body);
        Request oKRequest = builder.build();
        return execute(oKRequest);
    }

    /**
     * 请求执行过程
     *
     * @param request
     * @return
     */
    private IResponse execute(Request request) {
        BaseResponse commonResponse = new BaseResponse();
        try {
            Response response = mOkHttpClient.newCall(request).execute();
            // 1.设置状态码
            commonResponse.setCode(response.code());
            String body = response.body().string();
            // 2.设置响应数据体
            commonResponse.setData(body);
            /*Log.d("OkHttpClientImpl",String.format("Received response body: %s ",body));*/
        } catch (IOException e) {
            e.printStackTrace();
            //出错了
            commonResponse.setCode(commonResponse.STATE_UNKNOWN_ERROR);
            commonResponse.setData(e.getMessage());
        }
        return (IResponse) commonResponse;
    }

}

3.3 网络请求,单元测试类。

package com.example.android1.mytaxi.common.http.impl;

import com.example.android1.mytaxi.common.http.IHttpClient;
import com.example.android1.mytaxi.common.http.IRequest;
import com.example.android1.mytaxi.common.http.IResponse;
import com.example.android1.mytaxi.common.http.api.API;

import junit.framework.TestCase;
import org.junit.Before;
import org.junit.Test;

//网络请求,单元测试case。
public class OkHttpClientImplTest extends TestCase {
    IHttpClient httpClient;

    // 预先执行的方法,给httpClient赋值。
    @Before
    public void setUp() throws Exception {
        httpClient = new OkHttpClientImpl();
        API.Config.setDebug(true);
    }

    @Test
    public void testGet() {//测试get请求
        String url = API.Config.getDomain() + API.TEST_GET;
        IRequest request = new BaseRequest(url);
        request.setBody("uid", "abcd");
        request.setHeader("header", "test header 2025");
        //执行请求
        IResponse response = httpClient.get(request, false);
        System.out.println("code = " + response.getCode());
        System.out.println("body = " + response.getData());
    }
/* get服务器返回
* code = 200
body = {
  "args": {
    "uid": "abcd"
  },
  "headers": {
    "Accept-Encoding": "gzip",
    "Header": "test header 2025",
    "Host": "httpbin.org",
    "User-Agent": "okhttp/4.11.0",
    "X-Amzn-Trace-Id": "Root=1-68ac1a46-55a4a04a207f782a3c976682",
    "X-Bmob-Application-Id": "e90928398db0130b0d6d21da7bde357e",
    "X-Bmob-Rest-Api-Key": "514d8f8a2371bdf1566033f6664a24d2"
  },
  "origin": "118.250.98.191",
  "url": "http://httpbin.org/get?uid=abcd"
}*/

    @Test
    public void testPost() {//测试post请求
        String url = API.Config.getDomain() + API.TEST_POST;
        System.out.println("url = " + url);
        IRequest request = new BaseRequest(url);
        request.setBody("uid", "abcdpost");
        request.setHeader("header", "test header666 2025");
        //执行请求
        IResponse response = httpClient.post(request, false);
        System.out.println("code = " + response.getCode());
        System.out.println("body = " + response.getData());
    }
    /* post服务器返回
    * url = http://httpbin.org/post
code = 200
body = {
  "args": {},
  "data": "{\"uid\":\"abcdpost\"}",
  "files": {},
  "form": {},
  "headers": {
    "Accept-Encoding": "gzip",
    "Content-Length": "18",
    "Content-Type": "application/json; charset=utf-8",
    "Header": "test header666 2025",
    "Host": "httpbin.org",
    "User-Agent": "okhttp/4.11.0",
    "X-Amzn-Trace-Id": "Root=1-68ac19eb-50a3f71b7baec1625145211c",
    "X-Bmob-Application-Id": "e90928398db0130b0d6d21da7bde357e",
    "X-Bmob-Rest-Api-Key": "514d8f8a2371bdf1566033f6664a24d2"
  },
  "json": {
    "uid": "abcdpost"
  },
  "origin": "118.250.98.191",
  "url": "http://httpbin.org/post"
}
* */
}

相关文章

网友评论

      本文标题:okhttp封装,

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