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







网友评论