这是我参与11月更文挑战的第13天,活动详情查看:11月更文挑战
Java中Http请求的方式很多, OkHttpClient因其独特的特性,非常适合在常见的场景中使用.
1 OkHttpClient的简介
1 OkHttpClient说明
OkHttpClient是一个高效的HTTP客户端,其特性包含:
- 支持HTTP/2,允许所有同一个主机地址的请求共享同一个socket连接
- 连接池减少请求延时
- 透明的GZIP压缩减少响应数据的大小
- 缓存响应内容,避免一些完全重复的请求
2 OkHttpClient使用步骤
- 创建OkHttpClient对象
- 创建Request对象
- 将Request 对象封装为Call
- 通过Call 来执行同步或异步请求,调用execute方法同步执行,调用enqueue方法异步执行
3 OkHttpClient案例
@Slf4j
public class OkHttpDemo {
// 创建OkHttpClient对象, 并设置超时时间 添加拦截器LoginInterceptor
private static final OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.addInterceptor(new LoginInterceptor())
.build();
public static void main(String[] args) throws IOException {
String url = "http://www.baidu.com";
Request request = new Builder()
.url(url)
.get() // 不写,默认是GET请求
.build();
Call call = okHttpClient.newCall(request);
// 异步调用
call.enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
log.info("请求失败,异常信息为: {}", e.getMessage());
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response)
throws IOException {
log.info("请求成功,返回信息为: {}", response.body().toString());
}
});
}
}
Interceptor拦截器
@Slf4j
public class LoginInterceptor implements Interceptor {
/** * 统计登录接口完成时间 */
@NotNull
@Override
public Response intercept(@NotNull Chain chain) throws IOException {
Request request = chain.request();
long begin = System.currentTimeMillis();
Response response = chain.proceed(request);
long end = System.currentTimeMillis();
// 请求路径中有/login 统计花费时间
if (request.url().toString().contains("/login")) {
log.info("接口处理总用时: {} ", end - begin);
}
return response;
}
}
OkHttpClient对象
通过其内部类Builder的构造器模式,进行属性参数的初始化,常见的包括: 任务调度,协议,连接池,连接超时,读取超时等属性.
public static final class Builder {
@NotNull
private Dispatcher dispatcher;
@NotNull
private ConnectionPool connectionPool;
@NotNull
private final List interceptors;
private int callTimeout;
private int connectTimeout;
private int readTimeout;
private int writeTimeout;
private int pingInterval;
private long minWebSocketMessageToCompress;
@Nullable
private RouteDatabase routeDatabase;
}
Request对象
通过其内部类构造器模式,进行属性参数的初始化,常见的包括: 请求地址url,请求方式,请求头,请求体,标签参数等, 并且该构造中默认是GET请求.
open class Builder {
internal var url: HttpUrl? = null
internal var method: String
internal var headers: Headers.Builder
internal var body: RequestBody? = null
/** A mutable map of tags, or an immutable empty map if we don't have any. */
internal var tags: MutableMap<Class<*>, Any> = mutableMapOf()
constructor() {
this.method = "GET"
this.headers = Headers.Builder()
}
internal constructor(request: Request) {
this.url = request.url
this.method = request.method
this.body = request.body
this.tags = if (request.tags.isEmpty()) {
mutableMapOf()
} else {
request.tags.toMutableMap()
}
this.headers = request.headers.newBuilder()
}
}
Call对象
通过OkHttpClient和Request对象构造Call对象,Call接口的唯一实现类RealCall. 其execute方法表示同步执行, enqueue方法表示异步执行.
override fun execute(): Response {
check(executed.compareAndSet(false, true)) { "Already Executed" }
timeout.enter()
callStart()
try {
client.dispatcher.executed(this)
return getResponseWithInterceptorChain()
} finally {
client.dispatcher.finished(this)
}
}
override fun enqueue(responseCallback: Callback) {
check(executed.compareAndSet(false, true)) { "Already Executed" }
callStart()
client.dispatcher.enqueue(AsyncCall(responseCallback))
}
Interceptor拦截器
Interceptor为所有拦截器的接口, 其实现类有 桥接拦截器BridgeInterceptor, 缓存拦截器CacheInterceptor, 服务拦截器CallServerInterceptor, 错误、重定向拦截器RetryAndFollowUpInterceptor, 连接拦截器ConnectInterceptor.
Call中execute方法调用的getResponseWithInterceptorChain()方法, 创建一个拦截器集合容器,首先添加用户自定义的拦截器, 错误、重定向拦截器,桥接拦截器,缓存拦截器,连接拦截器,服务拦截器.
整个拦截器执行链路,按照添加先后顺序执行,即先执行用户自定义拦截器.
internal fun getResponseWithInterceptorChain(): Response {
// Build a full stack of interceptors.
val interceptors = mutableListOf<Interceptor>()
interceptors += client.interceptors
interceptors += RetryAndFollowUpInterceptor(client)
interceptors += BridgeInterceptor(client.cookieJar)
interceptors += CacheInterceptor(client.cache)
interceptors += ConnectInterceptor
if (!forWebSocket) {
interceptors += client.networkInterceptors
}
interceptors += CallServerInterceptor(forWebSocket)
val chain = RealInterceptorChain(
call = this,
interceptors = interceptors,
index = 0,
exchange = null,
request = originalRequest,
connectTimeoutMillis = client.connectTimeoutMillis,
readTimeoutMillis = client.readTimeoutMillis,
writeTimeoutMillis = client.writeTimeoutMillis
)
var calledNoMoreExchanges = false
try {
val response = chain.proceed(originalRequest)
if (isCanceled()) {
response.closeQuietly()
throw IOException("Canceled")
}
return response
} catch (e: IOException) {
calledNoMoreExchanges = true
throw noMoreExchanges(e) as Throwable
} finally {
if (!calledNoMoreExchanges) {
noMoreExchanges(null)
}
}
}
4 OkHttpClient常用工具类:
@Slf4j
public class OkHttpUtils {
// 创建OkHttpClient对象, 并设置超时时间
private static final OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.build();
/** * 同步GET请求 * * @param url 请求地址 */
public static String getRequest(String url) {
try {
// 1 创建OkHttpClient对象
// 2 构建Request对象
Request request = new Request.Builder()
.get()// 不写默认为GET请求
.url(url)
.build();
// 3 发起请求获取响应值
Response response = client.newCall(request).execute();
// 4 根据响应结果判断
if (response.isSuccessful()) {
return response.body().string();
} else {
throw new RuntimeException("请求异常,错误码为: " + response.code());
}
} catch (Exception e) {
log.info("请求失败,错误信息为= {} ", e.getMessage());
}
return null;
}
/** * 同步POST请求 * * @param url 请求地址 * @param params 请求参数 */
public static String postRequest(String url, Map<String, String> params) {
try {
// 1 创建OkHttpClient对象
// 2 构建请求体
MultipartBody body = new MultipartBody.Builder()
.setType(MediaType.parse("multipart/form-data"))
.addFormDataPart("username", params.get("username"))
.addFormDataPart("password", params.get("password"))
.build();
// 3 构建Request对象
Request request = new Request.Builder()
.post(body)
.url(url)
.build();
// 4 发起请求获取响应值
Response response = client.newCall(request).execute();
// 5 根据响应结果判断
if (response.isSuccessful()) {
return response.body().string();
} else {
throw new RuntimeException("请求异常,错误码为: " + response.code());
}
} catch (Exception e) {
log.info("请求失败,错误信息为= {} ", e.getMessage());
}
return null;
}
/** * 同步GET请求 */
public static String getRequest(String url) throws IOException {
Request request = new Builder().url(url).build();
Response response = execute(request);
if (response.isSuccessful()) {
return response.body().string();
} else {
throw new ArithmeticException("请求异常,错误码为: " + response.code());
}
}
/** * 同步请求 */
public static Response execute(Request request) throws IOException {
return client.newCall(request).execute();
}
/** * 开启异步线程访问网络, 需要返回结果 */
public static void enqueue(Request request, Callback callback) {
client.newCall(request).enqueue(callback);
}
/** * 开启异步线程访问网络,不需要返回结果( Callback 返回为空) */
public static void enqueue(Request request) {
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
log.info("请求失败,异常信息为: {} ", e.getMessage());
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response)
throws IOException {
log.info("请求成功");
}
});
}
}
参考资料:
今天的文章Java中发送Http请求之OkHttpClient分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/19780.html