Post请求
json数据提交
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Response response = client.newCall(request).execute();
}
FromBody---表单提交
//把参数传进Map中
HashMap<String,String> paramsMap=new HashMap<>();
paramsMap.put("name","哈哈");
paramsMap.put("client","Android");
paramsMap.put("id","3243598");
FormBody.Builder builder = new FormBody.Builder();
for (String key : paramsMap.keySet()) {
//追加表单信息
builder.add(key, paramsMap.get(key));
}
OkHttpClient okHttpClient=new OkHttpClient();
RequestBody formBody=builder.build();
Request request=new Request.Builder().url(netUrl).post(formBody).build();
MultipartBody---文件上传
-
Content-Type - 用于请求头的,固定用:form-data、mixed、alternative、digest、parallel。
- boundary - 每个字段/文件都被boundary(Content-Type中指定)分成单独的段
- 每个分段里面包含name,fileName(可空),contentType(可空),body这几个部分
OkHttpClient.Builder builder = new OkHttpClient.Builder();
OkHttpClient okHttpClient = builder.build();
//buidler构造方法可以传递一个string作为boundary
//不传会默认生成UUID作为boundary
MultipartBody.Builder multiBuilder=new MultipartBody.Builder();
//设置请求头的content-type
multiBuilder.setType(MultipartBody.FORM);
File file=new File(Environment.getExternalStorageDirectory(), "balabala.png");
MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
//第一个参数为分段的content-type类型
RequestBody filebody = RequestBody.create(MEDIA_TYPE_PNG, file);
//这里是 封装上传图片参数。参数分别是name,filename,body
multiBuilder.addFormDataPart("file", file.getName(), filebody);
//这是其他参数,都是无content-type和filename。第二个参数就是body
multiBuilder.addFormDataPart("client", "Android");
multiBuilder.addFormDataPart("uid", "1061");
multiBuilder.addFormDataPart("token", "1911173227afe098143caf4d315a436d");
multiBuilder.addFormDataPart("uuid", "A000005566DA77");
MultipartBody body = multiBuilder.build();
Request request = new Request.Builder()
.url("http://baidu.com")
.post(body)
.build();
Call call = okHttpClient.newCall(request);
Client配置
证书
信任所有的证书
okhttp默认用filter是抓不了包的,测试阶段抓包时需要添加配置:
/**
* 全部证书信任
* var allTrustManager = HttpsUtils.AllTrustManager()
* var createAllTrustSocketFactory = HttpsUtils.createAllTrustSocketFactory(allTrustManager)
*
*var build = OkHttpClient.Builder()
* .sslSocketFactory(createAllTrustSocketFactory, allTrustManager)
* .build()
* @return
*/
public static SSLSocketFactory createAllTrustSocketFactory(TrustManager manager) {
SSLSocketFactory ssfFactory = null;
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, new TrustManager[]{manager}, new SecureRandom());
ssfFactory = sc.getSocketFactory();
} catch (Exception ignored) {
ignored.printStackTrace();
}
return ssfFactory;
}
public static class AllTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
支持自签名
项目不是用ca证书,而是自生成的证书
public class CertificateUtils {
public static void setClientSslSocket(OkHttpClient.Builder builder,String certFileName,String passWord){
try {
InputStream open = Utils.getApp().getAssets().open(certFileName);
X509TrustManager x509TrustManager = trustManagerForCertificates(open, passWord);
SSLContext tls = SSLContext.getInstance("TLS");
tls.init(null,new TrustManager[]{x509TrustManager},null);
SSLSocketFactory socketFactory = tls.getSocketFactory();
builder.sslSocketFactory(socketFactory);
} catch (GeneralSecurityException | IOException e) {
e.printStackTrace();
}
}
/**
*
* @param in
* @param password
* @return
* @throws GeneralSecurityException
*/
public static X509TrustManager trustManagerForCertificates(InputStream in, String password)
throws GeneralSecurityException {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
//通过证书工厂得到自签证书对象集合
Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(in);
if (certificates.isEmpty()) {
throw new IllegalArgumentException("expected non-empty set of trusted certificates");
}
//为证书设置一个keyStore
char[] passwordChar = password.toCharArray(); // Any password will work.
KeyStore keyStore = newEmptyKeyStore(passwordChar);
int index = 0;
//将证书放入keystore中
for (Certificate certificate : certificates) {
String certificateAlias = Integer.toString(index++);
keyStore.setCertificateEntry(certificateAlias, certificate);
}
// Use it to build an X509 trust manager.
//使用包含自签证书信息的keyStore去构建一个X509TrustManager
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, passwordChar);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
throw new IllegalStateException("Unexpected default trust managers:"
+ Arrays.toString(trustManagers));
}
return (X509TrustManager) trustManagers[0];
}
private static KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException {
try {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
// By convention, 'null' creates an empty key store.
keyStore.load(null, password);
return keyStore;
} catch (IOException e) {
throw new AssertionError(e);
}
}
}
代理
//代理服务器的IP和端口号
//优先于proxySelector,设置了proxySelector就会失效
builder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8080)));
//默认取系统的代理(ProxySelector.getDefault()),防转包可以设置成空
NullProxySelector nullProxySelector = new NullProxySelector();
builder.proxySelector(nullProxySelector)
//代理的鉴权账号密码
final String userName = "";
final String password = "";
builder.proxyAuthenticator(new Authenticator() {
@Override
public Request authenticate(Route route, Response response) throws IOException {
//设置代理服务器账号密码
String credential = Credentials.basic(userName, password);
return response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build();
}
});
同步异步调度池
Dispatcher dispatcher = new Dispatcher();
dispatcher.setMaxRequests(64);
dispatcher.setMaxRequestsPerHost(5);
//闲置的回调
dispatcher.setIdleCallback(() -> {
LogUtils.i("没有在运行的请求");
});
builder .dispatcher(dispatcher)
协议
List<Protocol> protocols = Util.immutableList(
Protocol.HTTP_2, Protocol.HTTP_1_1,Protocol.HTTP_1_0);
List<ConnectionSpec> DEFAULT_CONNECTION_SPECS = Util.immutableList(
ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT);
//支持的应用层协议,默认支持http2和http1.1
builder .protocols(protocols)
//支持的连接协议,主要是tls的协议
builder.connectionSpecs(DEFAULT_CONNECTION_SPECS)
连接池
maxIdleConnections - 每个address的最大空闲连接数
keepAliveDurationNs - 空闲连接的保活时间
ConnectionPool connectionPool = new ConnectionPool(5, 60, TimeUnit.SECONDS);
builder.connectionPool(connectionPool);
其他
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.addInterceptor()//插在最前面
//插在ConnectionInterceptor后
.addNetworkInterceptor()
//全局事件监听
.eventListener(new OkHttpListener());
//TLS域名验证,设为true就可以抓包
.hostnameVerifier((hostname, session) -> true)
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
//失败重试,默认ture
.retryOnConnectionFailure(true)
//重定向,默认ture
.followRedirects(true)
//TLS重定向,默认ture
.followSslRedirects(true);