淺談HttpClient、okhttp和RestTemplate的區(qū)別
一、HttpClient
1、pom依賴
<!--HttpClient-->
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
2、HttpClient代碼實(shí)現(xiàn)
public class HttpClientUtil {
/**
* httpClient的get請求方式
* 使用GetMethod來訪問一個URL對應(yīng)的網(wǎng)頁實(shí)現(xiàn)步驟:
* 1.生成一個HttpClient對象并設(shè)置相應(yīng)的參數(shù);
* 2.生成一個GetMethod對象并設(shè)置響應(yīng)的參數(shù);
* 3.用HttpClient生成的對象來執(zhí)行GetMethod生成的Get方法;
* 4.處理響應(yīng)狀態(tài)碼;
* 5.若響應(yīng)正常,處理HTTP響應(yīng)內(nèi)容;
* 6.釋放連接。
* @param url
* @param charset
* @return
*/
public static String doGet(String url, String charset) {
//1.生成HttpClient對象并設(shè)置參數(shù)
HttpClient httpClient = new HttpClient();
//設(shè)置Http連接超時為5秒
httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
//2.生成GetMethod對象并設(shè)置參數(shù)
GetMethod getMethod = new GetMethod(url);
//設(shè)置get請求超時為5秒
getMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, 5000);
//設(shè)置請求重試處理,用的是默認(rèn)的重試處理:請求三次
getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());
String response = "";
//3.執(zhí)行HTTP GET 請求
try {
int statusCode = httpClient.executeMethod(getMethod);
//4.判斷訪問的狀態(tài)碼
if (statusCode != HttpStatus.SC_OK) {
System.err.println("請求出錯:" + getMethod.getStatusLine());
}
//5.處理HTTP響應(yīng)內(nèi)容
//HTTP響應(yīng)頭部信息,這里簡單打印
Header[] headers = getMethod.getResponseHeaders();
for(Header h : headers) {
System.out.println(h.getName() + "---------------" + h.getValue());
}
//讀取HTTP響應(yīng)內(nèi)容,這里簡單打印網(wǎng)頁內(nèi)容
//讀取為字節(jié)數(shù)組
byte[] responseBody = getMethod.getResponseBody();
response = new String(responseBody, charset);
System.out.println("-----------response:" + response);
//讀取為InputStream,在網(wǎng)頁內(nèi)容數(shù)據(jù)量大時候推薦使用
//InputStream response = getMethod.getResponseBodyAsStream();
} catch (HttpException e) {
//發(fā)生致命的異常,可能是協(xié)議不對或者返回的內(nèi)容有問題
System.out.println("請檢查輸入的URL!");
e.printStackTrace();
} catch (IOException e) {
//發(fā)生網(wǎng)絡(luò)異常
System.out.println("發(fā)生網(wǎng)絡(luò)異常!");
} finally {
//6.釋放連接
getMethod.releaseConnection();
}
return response;
}
/**
* post請求
* @param url
* @param json
* @return
*/
public static String doPost(String url, JSONObject json){
HttpClient httpClient = new HttpClient();
PostMethod postMethod = new PostMethod(url);
postMethod.addRequestHeader("accept", "*/*");
postMethod.addRequestHeader("connection", "Keep-Alive");
//設(shè)置json格式傳送
postMethod.addRequestHeader("Content-Type", "application/json;charset=GBK");
//必須設(shè)置下面這個Header
postMethod.addRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36");
//添加請求參數(shù)
postMethod.addParameter("commentId", json.getString("commentId"));
String res = "";
try {
int code = httpClient.executeMethod(postMethod);
if (code == 200){
res = postMethod.getResponseBodyAsString();
System.out.println(res);
}
} catch (IOException e) {
e.printStackTrace();
}
return res;
}
public static void main(String[] args) {
System.out.println(doGet("http://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=13026194071", "GBK"));
System.out.println("-----------分割線------------");
System.out.println("-----------分割線------------");
System.out.println("-----------分割線------------");
JSONObject jsonObject = new JSONObject();
jsonObject.put("commentId", "13026194071");
System.out.println(doPost("http://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=13026194071", jsonObject));
}
}
3、建議
代碼復(fù)雜,還得操心資源回收等。代碼很復(fù)雜,冗余代碼多,不建議直接使用。
二、okhttp
1、簡介
OkHttp是一個高效的HTTP客戶端,允許所有同一個主機(jī)地址的請求共享同一個socket連接;連接池減少請求延時;透明的GZIP壓縮減少響應(yīng)數(shù)據(jù)的大?。痪彺骓憫?yīng)內(nèi)容,避免一些完全重復(fù)的請求
當(dāng)網(wǎng)絡(luò)出現(xiàn)問題的時候OkHttp依然堅(jiān)守自己的職責(zé),它會自動恢復(fù)一般的連接問題,如果你的服務(wù)有多個IP地址,當(dāng)?shù)谝粋€IP請求失敗時,OkHttp會交替嘗試你配置的其他IP,OkHttp使用現(xiàn)代TLS技術(shù)(SNI, ALPN)初始化新的連接,當(dāng)握手失敗時會回退到TLS 1.0。
2、pom依賴
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.10.0</version>
</dependency>
它的請求/響應(yīng) API 使用構(gòu)造器模式builders來設(shè)計(jì),它支持阻塞式的同步請求和帶回調(diào)的異步請求。
3、配置文件
@Configuration
public class OkHttpConfig {
@Bean
public OkHttpClient okHttpClient() {
return new OkHttpClient.Builder()
//.sslSocketFactory(sslSocketFactory(), x509TrustManager())
.retryOnConnectionFailure(false)
.connectionPool(pool())
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30,TimeUnit.SECONDS)
.build();
}
@Bean
public X509TrustManager x509TrustManager() {
return new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
}
@Bean
public SSLSocketFactory sslSocketFactory() {
try {
//信任任何鏈接
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{x509TrustManager()}, new SecureRandom());
return sslContext.getSocketFactory();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
return null;
}
/**
* Create a new connection pool with tuning parameters appropriate for a single-user application.
* The tuning parameters in this pool are subject to change in future OkHttp releases. Currently
*/
@Bean
public ConnectionPool pool() {
return new ConnectionPool(200, 5, TimeUnit.MINUTES);
}
}
4、客戶端工具
@Slf4j
public class OkHttpClient {
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
private volatile static okhttp3.OkHttpClient client;
private static final int MAX_IDLE_CONNECTION = Integer
.parseInt(ConfigManager.get("httpclient.max_idle_connection"));
private static final long KEEP_ALIVE_DURATION = Long
.parseLong(ConfigManager.get("httpclient.keep_alive_duration"));
private static final long CONNECT_TIMEOUT = Long.parseLong(ConfigManager.get("httpclient.connectTimeout"));
private static final long READ_TIMEOUT = Long.parseLong(ConfigManager.get("httpclient. "));
/**
* 單例模式(雙重檢查模式) 獲取類實(shí)例
*
* @return client
*/
private static okhttp3.OkHttpClient getInstance() {
if (client == null) {
synchronized (okhttp3.OkHttpClient.class) {
if (client == null) {
client = new okhttp3.OkHttpClient.Builder()
.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(MAX_IDLE_CONNECTION, KEEP_ALIVE_DURATION,
TimeUnit.MINUTES))
.build();
}
}
}
return client;
}
public static String syncPost(String url, String json) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
try {
Response response = OkHttpClient.getInstance().newCall(request).execute();
if (response.isSuccessful()) {
String result = response.body().string();
log.info("syncPost response = {}, responseBody= {}", response, result);
return result;
}
String result = response.body().string();
log.info("syncPost response = {}, responseBody= {}", response, result);
throw new IOException("三方接口返回http狀態(tài)碼為" + response.code());
} catch (Exception e) {
log.error("syncPost() url:{} have a ecxeption {}", url, e);
throw new RuntimeException("syncPost() have a ecxeption {}" + e.getMessage());
}
}
public static String syncGet(String url, Map<String, Object> headParamsMap) throws IOException {
Request request;
final Request.Builder builder = new Request.Builder().url(url);
try {
if (!CollectionUtils.isEmpty(headParamsMap)) {
final Iterator<Map.Entry<String, Object>> iterator = headParamsMap.entrySet()
.iterator();
while (iterator.hasNext()) {
final Map.Entry<String, Object> entry = iterator.next();
builder.addHeader(entry.getKey(), (String) entry.getValue());
}
}
request = builder.build();
Response response = OkHttpClient.getInstance().newCall(request).execute();
String result = response.body().string();
log.info("syncGet response = {},responseBody= {}", response, result);
if (!response.isSuccessful()) {
throw new IOException("三方接口返回http狀態(tài)碼為" + response.code());
}
return result;
} catch (Exception e) {
log.error("remote interface url:{} have a ecxeption {}", url, e);
throw new RuntimeException("三方接口返回異常");
}
}
}
三、RestTemplate
1、pom依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2、get請求(不帶參的即把參數(shù)取消即可)
// 1-getForObject() User user1 = this.restTemplate.getForObject(uri, User.class); // 2-getForEntity() ResponseEntity<User> responseEntity1 = this.restTemplate.getForEntity(uri, User.class); HttpStatus statusCode = responseEntity1.getStatusCode(); HttpHeaders header = responseEntity1.getHeaders(); User user2 = responseEntity1.getBody(); // 3-exchange() RequestEntity requestEntity = RequestEntity.get(new URI(uri)).build(); ResponseEntity<User> responseEntity2 = this.restTemplate.exchange(requestEntity, User.class); User user3 = responseEntity2.getBody();
方式一:
Notice notice = restTemplate.getForObject("http://fantj.top/notice/list/{1}/{2}"
, Notice.class,1,5);
方式二:
Map<String,String> map = new HashMap();
map.put("start","1");
map.put("page","5");
Notice notice = restTemplate.getForObject("http://fantj.top/notice/list/"
, Notice.class,map);
3、post請求
// 1-postForObject() User user1 = this.restTemplate.postForObject(uri, user, User.class); // 2-postForEntity() ResponseEntity<User> responseEntity1 = this.restTemplate.postForEntity(uri, user, User.class); // 3-exchange() RequestEntity<User> requestEntity = RequestEntity.post(new URI(uri)).body(user); ResponseEntity<User> responseEntity2 = this.restTemplate.exchange(requestEntity, User.class);
方式一:
String url = "http://demo/api/book/";
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
headers.setContentType(type);
String requestJson = "{...}";
HttpEntity<String> entity = new HttpEntity<String>(requestJson,headers);
String result = restTemplate.postForObject(url, entity, String.class);
System.out.println(result);
方式二:
@Test
public void rtPostObject(){
RestTemplate restTemplate = new RestTemplate();
String url = "http://47.xxx.xxx.96/register/checkEmail";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map= new LinkedMultiValueMap<>();
map.add("email", "844072586@qq.com");
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
ResponseEntity<String> response = restTemplate.postForEntity( url, request , String.class );
System.out.println(response.getBody());
}
使用RestTemplate需注意:
使用RestTemplate發(fā)送請求,當(dāng)請求體是String時,應(yīng)這樣配置:
RestTemplate restTemplate = new RestTemplate(factory);
restTemplate
.getMessageConverters()
.set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
如果沒有自定義StringHttpMessageConverter,默認(rèn)的StringHttpMessageConverter使用的字符集是ISO_8859_1,當(dāng)請求體包含中文時,會亂碼。
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
@scope("prototype") @loadbalanced注解負(fù)載均衡失效問題
這篇文章主要為大家介紹了@scope("prototype") @loadbalanced注解負(fù)載均衡失效問題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02
Springcloud GateWay網(wǎng)關(guān)配置過程圖解
這篇文章主要介紹了Springcloud GateWay網(wǎng)關(guān)配置過程圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-12-12
Java中Elasticsearch 實(shí)現(xiàn)分頁方式(三種方式)
Elasticsearch是用Java語言開發(fā)的,并作為Apache許可條款下的開放源碼發(fā)布,是一種流行的企業(yè)級搜索引擎,這篇文章主要介紹了Elasticsearch實(shí)現(xiàn)分頁的3種方式,需要的朋友可以參考下2022-07-07
Spring boot按日切分spring boot的nohup.out日志文件的方法
過大的日志文件維護(hù)起來存在諸多問題,所以最好是能夠按日或按大小切分日志文件,下面小編給大家?guī)砹薙pring boot按日切分spring boot的nohup.out日志文件的方法,一起看看吧2018-08-08
關(guān)于mybatis調(diào)用存儲過程獲取返回值問題
這篇文章主要介紹了mybatis調(diào)用存儲過程獲取返回值問題,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-01-01
MyBatis-Plus 自動填充的實(shí)現(xiàn)示例
MyBatis-Plus 提供了自動填充功能,幫助開發(fā)者在插入或更新數(shù)據(jù)時,自動為某些字段賦值,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-09-09
SpringBoot 使用 @Value 注解讀取配置文件給靜態(tài)變量賦值
這篇文章主要介紹了SpringBoot 使用 @Value 注解讀取配置文件給靜態(tài)變量賦值,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
SpringBoot多環(huán)境配置及配置文件分類實(shí)例詳解
這篇文章主要介紹了SpringBoot多環(huán)境配置及配置文件分類,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-10-10

