需求使然,需要后端使用Java访问特定的第三方接口来进行请求,而这些接口则需要使用Http协议访问。所以归纳了一下目前Java主流的Http访问的三种方式。
第一种:JDK提供 使用java.net.HttpURLConnection
先上代码
/**
* 第一种:java.net
*/
public class HttpConnect {
public static String post(String urlStr, String data){
try {
URL url = new URL(urlStr);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json; charset=utf-8");
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setUseCaches(false);
DataOutputStream dataOutputStream = new DataOutputStream(connection.getOutputStream());
JSONObject jsonObject = JSON.parseObject(data);
dataOutputStream.writeBytes(jsonObject.toJSONString());
dataOutputStream.flush();
dataOutputStream.close();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder result = new StringBuilder();
String line;
while((line = reader.readLine()) != null){
result.append(line);
}
reader.close();
connection.disconnect();
return result.toString();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static String get(String strUrl){
try {
// 传入参数
// String realUrl = strUrl;
URL url = new URL(strUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 在连接之前设置各种属性
// Content-Type实体头用于向接收方指示实体的介质类型,指定HEAD方法送到接收方的实体介质类型,或GET方法发送的请求介质类型
conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
// 设置打开与此URLConnection引用的资源的通信链接时使用的指定超时值(以毫秒为单位)
conn.setConnectTimeout(10000);
// 将读取超时设置为指定的超时时间,以毫秒为单位。
// conn.setReadTimeout(60000);
conn.setRequestMethod("GET");
conn.setUseCaches(false);
// 建立连接
conn.connect();
// 获取响应
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
StringBuilder result = new StringBuilder();
while ((line = reader.readLine()) != null) {
result.append(line);
}
reader.close();
conn.disconnect();
return result.toString();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
使用URL对象打开连接,也就是HttpURLConnection对象,然后设置各种属性。
建立连接后,喜闻乐见的要获取各种流,通过流来获取Http协议传来的各种Data。
繁琐且麻烦
第二种:HttpClient 是Apache的开源Http请求包
/**
* apache HttpClient
*/
public class HttpClientTest {
public static String get(String urlStr){
// 创建HttpClient对象
CloseableHttpClient client = HttpClients.createDefault();
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(30000) // 各种参数设置,这里是请求超时时间
.build();
HttpGet get = new HttpGet(urlStr);
get.setConfig(config);
String result = "";
try {
CloseableHttpResponse response = client.execute(get);
if (response.getStatusLine().getStatusCode() == 200){
result = EntityUtils.toString(response.getEntity());
return result;
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
public static String post(String urlStr, String jsonStr){
CloseableHttpClient client = HttpClients.createDefault();
HttpPost post = new HttpPost(urlStr);
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(30*1000)
.build();
post.setConfig(requestConfig);
post.setHeader("Content-Type","application/json");
post.setEntity(new StringEntity(jsonStr, ContentType.create("application/json", "utf-8")));
String result = "";
try {
CloseableHttpResponse response = client.execute(post);
if (response.getStatusLine().getStatusCode() == 200){
result = EntityUtils.toString(response.getEntity());
return result;
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
百度上是这么写的:
(1)实现了所有 HTTP 的方法(GET,POST,PUT,HEAD 等)
(2)支持自动转向
(3)支持 HTTPS 协议
(4)支持代理服务器等
封装了JDK繁琐的流操作,而且配置使用Builder方式,让代码更清晰好看。对请求返回Code封装了对象,可以通过Code判断请求状态。POST请求可以传入Json字符串,也可以传入List
第三种:OkHttp3 #本人最喜欢的
2019-09-05 更新,重新更改代码结构,并增加新的方法,以便复制即可使用
/**
* OkHttp
*/
public static String get(String url) throws IOException {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(30L, TimeUnit.SECONDS)
.build();
final Request request = new Request.Builder()
.url(url)
.get()
.build();
final Call call = okHttpClient.newCall(request);
ResponseBody body = call.execute().body();
return formatResponse(body);
}
public static String post(String url, String requestBody) throws IOException {
MediaType media = MediaType.parse("application/json;charset=utf-8");
return post(url, requestBody, media);
}
/**
* 上传文件
*/
public static String post(String url, File file) throws IOException {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(30L, TimeUnit.SECONDS)
.build();
MediaType media = MediaType.parse("multipart/form-data");
RequestBody requestBody = RequestBody.create(file, media);
MultipartBody multipartBody = new MultipartBody.Builder()
// 设置type为"multipart/form-data"
.setType(MultipartBody.FORM)
.addFormDataPart("file", file.getName(), requestBody)
.build();
Request request = new Request.Builder()
.url(url)
.post(multipartBody)
.build();
Call call = okHttpClient.newCall(request);
ResponseBody body = call.execute().body();
return formatResponse(body);
}
private static String post(String url, String requestBody, MediaType media) throws RuntimeException, IOException {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(30L, TimeUnit.SECONDS)
.build();
Request request = new Request.Builder()
.url(url)
.post(RequestBody.create(requestBody, media))
.build();
Call call = okHttpClient.newCall(request);
ResponseBody body = call.execute().body();
return formatResponse(body);
}
private static String formatResponse(ResponseBody body) throws IOException {
final StringBuilder stringBuilder = new StringBuilder();
// 同步请求
if (body != null){
stringBuilder.append(body.string());
}
return stringBuilder.toString();
}
同样的,已经封装了任何流的操作,使用Builder创建连接对象。更方便地,可以根据需求决定使用同步请求还是异步请求。异步请求时,OkHttp会要求构造回调函数,这种清晰直观的设计让人不管观看还是使用,都很舒服。
使用POST请求时,也有封装的RequestBody,进行参数设置。
事实上,OkHttp的优点主要是:(官网的说明)
支持HTTP/2,允许所有同一个主机地址的请求共享同一个socket连接
连接池减少请求延时(如果Http2 不可用)
透明的GZIP压缩减少响应数据的大小
缓存响应内容,避免一些完全重复的请求
OkHttp最精髓的部分是他的拦截器。在创建HttpClient对象时,可以加上
.addInterceptor(new Interceptor()/* 该类的实现类*/)
就可以拦截这个请求,并做一些不为人知的事。嘿嘿~
只需要实现
public abstract Response intercept(Chain chain) throws IOException;
这个方法,就可以了,更多具体使用方法,可以参考官方API文档,这里不多作赘述。
附上链接
就是这样,附上本文参考资料。