使用OkHttp发送HTTP请求
2019-12-03 本文已影响0人
SevenLin1993
技术公众号:Java In Mind(Java_In_Mind),欢迎关注!
OkHttp简介
OkHttp是一个用于Android、Kotlin、Java的HTTP客户端,性能高效,API封装友好,主要有如下特点:
- 支持HTTP/2对同个服务端的请求共享一个Socket
- 使用连接池可减少请求延迟(HTTP / 2不可用)
- 使用GZIP缩小下载量
- 缓存响应结果防止网络重复请求
使用OkHttp,在网络出现问题的时候,它会将常见的连接问题恢复;
如果服务端拥有多个IP,OkHttp会在请求失败的情况下尝试其他IP,这对于IPv4 + IPv6数据中心中托管的多活服务是很有必要的;
OkHttp支持TLS功能;
OkHttp的API设计对开发者友好,设计为链式风格的Builder,并且支持同步阻塞调用和异步回调调用。
OkHttp4
OkHttp4.x在2019年6月份正式发布,从Java语言变为Kotlin语言,使用了Kotlin的一些高效语法,并且保持和OkHttp3一样的功能,为了保持兼容性以便升级,保持了二进制兼容、Java源码兼容和Kotlin源码兼容,使用japicmp强制执行二进制兼容性,并且报名保持为okhttp3,升级在方法也提供了升级指导:https://square.github.io/okhttp/upgrading_to_okhttp_4/
这里使用OkHttp3来简单使用一下:
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.14.4</version>
</dependency>
模拟服务
@RestController
@RequestMapping("/demo")
@SpringBootApplication
@Slf4j
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
private List<Foo> foos = new CopyOnWriteArrayList<>();
@GetMapping("/list")
public ResponseEntity list(@RequestParam(value = "name", required = false) String name) {
log.info("accept a list request...");
boolean emptyQuery = StringUtils.isEmpty(name);
return ResponseEntity
.ok(foos.stream().filter(i -> emptyQuery || i.getName().equals(name)).collect(Collectors.toList()));
}
@PostMapping
public ResponseEntity create(@RequestBody Foo foo) {
log.info("accept create request,foo:{}", foo);
// uuid
foo.setId(UUID.randomUUID().toString());
// add
foos.add(foo);
return ResponseEntity.ok(foo);
}
@GetMapping("/error")
public ResponseEntity error() {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("error");
}
@Data
@AllArgsConstructor
public static class Foo {
private String id;
private String name;
private int age;
}
}
发起POST请求
OkHttpClient okHttpClient = new OkHttpClient();
// request body
Map<String, String> foo = new HashMap<>();
foo.put("name", "HTTP");
foo.put("age", "18");
Request request = new Request.Builder().url("http://localhost:8080/demo")
.post(RequestBody.create(MediaType.get("application/json"), JSONObject.toJSONString(foo))).build();
try (Response response = okHttpClient.newCall(request).execute()) {
ResponseBody body = response.body();
if (response.isSuccessful()) {
log.info("success:{}", body == null ? "" : body.string());
} else {
log.error("error,statusCode={},body={}", response.code(), body == null ? "" : body.string());
}
}
发起GET请求
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder().url("http://localhost:8080/demo/list").build();
try (Response response = okHttpClient.newCall(request).execute()) {
ResponseBody body = response.body();
if (response.isSuccessful()) {
log.info("success:{}", body == null ? "" : body.string());
} else {
log.error("error,statusCode={},body={}", response.code(), body == null ? "" : body.string());
}
}
发起GET请求带查询参数
OkHttpClient okHttpClient = new OkHttpClient();
HttpUrl httpUrl = HttpUrl.parse("http://localhost:8080/demo/list").newBuilder()
.addQueryParameter("name", "HTTP").build();
Request request = new Request.Builder().url(httpUrl.toString()).build();
try (Response response = okHttpClient.newCall(request).execute()) {
ResponseBody body = response.body();
if (response.isSuccessful()) {
log.info("success:{}", body == null ? "" : body.string());
} else {
log.error("error,statusCode={},body={}", response.code(), body == null ? "" : body.string());
}
}
其他配置
-
设置超时
OkHttpClient okHttpClient = new OkHttpClient.Builder() .connectTimeout(Duration.ofSeconds(10))//连接超时 .writeTimeout(Duration.ofSeconds(5))//写超时,也就是请求超时 .readTimeout(Duration.ofSeconds(5))//读取超时 .callTimeout(Duration.ofSeconds(15))//调用超时,也是整个请求过程的超时 .build();
-
使用拦截器设置全局Header
//自定义拦截器,设置header public static class DefaultContentTypeInterceptor implements Interceptor { private String contentType; public DefaultContentTypeInterceptor(String contentType) { this.contentType = contentType; } public Response intercept(Interceptor.Chain chain) throws IOException { Request originalRequest = chain.request(); Request requestWithUserAgent = originalRequest .newBuilder() .header("Content-Type", contentType) .build(); return chain.proceed(requestWithUserAgent); } } // 设置 OkHttpClient httpClient = new OkHttpClient.Builder() .addInterceptor(new DefaultContentTypeInterceptor("application/json")) .build();
-
Basic 认证
OkHttpClient okHttpClient = new OkHttpClient.Builder().authenticator(new Authenticator() { @Override public Request authenticate(Route route, Response response) throws IOException { if (response.request().header("Authorization") != null) { return null; } String credential = Credentials.basic("username", "password"); return response.request().newBuilder().header("Authorization", credential).build(); } }).build();
总结
这里只做了简单的使用,OkHttp还有许多功能,请求缓存、异步回调等,OkHttp的API相对来说比较友好,可能也是我自己喜欢这种链式调用和Builder的模式,对于发起HTTP请求对Request的封装到Response的封装,结果的解析都比较简单,也支持用户自定义一些拦截做设置等。