1. RestTemplate
首先引入依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
編寫配置類
@Configuration
public class RestTemplateConfig {@Beanpublic RestTemplate restTemplate(ClientHttpRequestFactory factory){return new RestTemplate(factory);}@Beanpublic ClientHttpRequestFactory simpleClientHttpRequestFactory(){SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();factory.setReadTimeout(5000);//單位為msfactory.setConnectTimeout(5000);//單位為msreturn factory;}
}
SimpleClientHttpRequestFactory類對應的HTTP庫是JDK自帶的HttpUrlConnection,也可以修改使用其他的HTTP庫,例如HttpComponentsAsyncClientHttpRequestFactory。
這樣就可以注入使用了
@Resourceprivate RestTemplate restTemplate;
String url = "http://127.0.0.1/test";// 請求參數Map map = new HashMap<>();map.put("key", "111");// 設置請求頭屬性HttpHeaders httpHeaders = new HttpHeaders();httpHeaders.setContentType(MediaType.APPLICATION_JSON);HttpEntity httpEntity = new HttpEntity(map, httpHeaders);String results = restTemplate.postForObject(url, httpEntity, String.class);
2.?WebClient
?Spring3.0引入了RestTemplate,WebClient是Spring Framework的一部分,但是在后來的官方源碼中介紹,RestTemplate有可能在未來的版本中被棄用,所謂替代RestTemplate,在Spring5中引入了WebClient作為異步的非阻塞、響應式的HTTP客戶端。
依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
使用
public class TestWebClient {@Testpublic void doGet() {String userId = "郭郭";String url = "http://127.0.0.1:8094/masterdata/sysUser/getSysUserById?userId={userId}";Mono<String> mono = WebClient//創建WebClient實例.create()//方法調用,WebClient中提供了多種方法.get()//請求url.uri(url, userId)//獲取響應結果.retrieve()//將結果轉換為指定類型.bodyToMono(String.class);//返回最終結果:block是阻塞的/subscribe()非阻塞式獲取響應結果System.out.println("響應結果:" + mono.block());}@Testpublic void doPost() {Map map = new HashMap<>();map.put("name", "郭郭");String requestBody = JSON.toJSONString(map);String url = "http://127.0.0.1:8094/masterdata/sysUser/saveUser";Mono<String> mono = WebClient//創建WebClient實例.create()//方法調用,WebClient中提供了多種方法.post()//請求url.uri(url)//指定請求的Content-Type為JSON.contentType(MediaType.APPLICATION_JSON)//使用bodyValue方法傳遞請求體.bodyValue(requestBody)//獲取響應結果.retrieve()//將結果轉換為指定類型.bodyToMono(String.class);//返回最終結果:block是阻塞的/subscribe()非阻塞式獲取響應結果System.out.println("響應結果:" + mono.block());}
}
?在上述doPost請求中,我們的請求接口入參是一個Map,但是需要轉換為JSON格式傳遞,這是因為WebClient默認是使用JSON序列化的。
3.Apache HttpClient
引入依賴
<!-- 此處使用的是 5.x 版本,可以根據自身情況引入版本 --><dependency><groupId>org.apache.httpcomponents.client5</groupId><artifactId>httpclient5</artifactId><version>5.1.1</version></dependency>
//步驟一:方式1獲取默認配置的httpClient實例
CloseableHttpClient httpClient = HttpClients.createDefault();
// 方式2根據系統配置創建 HttpClient
// CloseableHttpClient httpClient = HttpClients.createSystem();
// 在項目啟動時可以通過設置如下JVM啟動參數:
// http.agent 配置 userAgent
// http.keepAlive 配置 keepAlive 數據
// 方式3自定義創建全局配置
// CloseableHttpClient httpClient = HttpClients.custom()
// .setDefaultHeaders(Collections.emptyList()) // 設置默認請求頭
// .setDefaultRequestConfig(RequestConfig.DEFAULT) // 設置默認配置
// .build();// 設置默認請求頭
List<Header> headers = new ArrayList<>();
headers.add(new BasicHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON));
headers.add(new BasicHeader(HttpHeaders.ACCEPT_ENCODING, "gzip, x-gzip, deflate"));
headers.add(new BasicHeader(HttpHeaders.CONNECTION, "keep-alive"));
httpClient .setDefaultHeaders(headers)
//步驟二:創建HTTP請求
HttpGet httpGet = new HttpGet("http://127.0.0.1:8080/masterdata/sysUser/getSysUserById?userId=張三");// 創建請求配置信息
RequestConfig requestConfig = RequestConfig.custom()
// 設置連接超時時間
.setConnectTimeout(Timeout.of(3000, TimeUnit.MILLISECONDS))
// 設置響應超時時間
.setResponseTimeout(3000, TimeUnit.MILLISECONDS)
// 設置從連接池獲取鏈接的超時時間
.setConnectionRequestTimeout(3000, TimeUnit.MILLISECONDS)
.build();
// 設置請求參數
httpGet.setConfig(requestConfig);
// 添加 Content-Type 請求頭
httpPost.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED);
// 添加 accept 請求頭
httpPost.addHeader(new BasicHeader(HttpHeaders.ACCEPT, "*/*"));
//步驟三:發送請求并獲取響應數據
CloseableHttpResponse response = httpClient.execute(httpGet);
// 獲取請求狀態
int code = response.getCode();
//步驟四:處理響應數據
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity);
//步驟五:關閉httpClient和response
response.close();
httpClient.close();
?通過 URIBuilder 構建請求路徑
// 構建請求路徑,及參數
URL url = new URL("http://localhost:10010/user/params");
URI uri = new URIBuilder()
.setScheme(url.getProtocol())
.setHost(url.getHost())
.setPort(url.getPort())
.setPath(url.getPath())
// 構建參數
.setParameters(
new BasicNameValuePair("name", "張三"),
new BasicNameValuePair("age", "20")
).build();
?
// 創建 GET 請求對象
HttpGet httpGet = new HttpGet(uri);
// 調用 HttpClient 的 execute 方法執行請求
CloseableHttpResponse response = httpClient.execute(httpGet);
// 獲取請求狀態
int code = response.getCode();
// 如果請求成功
if(code == HttpStatus.SC_OK){
http://LOGGER.info("響應結果為:{}", EntityUtils.toString(response.getEntity()));
}
發送 JSON 數據
HttpClient 中發送 JSON 數據可以使用 StringHttpEntity 類實現,如下所示:
// 請求參數
String url = "http://localhost:10010/user/body";
// 創建 GET 請求對象
HttpPost httpPost = new HttpPost(url);
// 構建對象
User user = new User();
user.setName("張三")
.setAge(20)
.setAddress(new Address()
.setCounty("中國")
.setCity("北京"))
.setAihao(Arrays.asList("跑步", "爬山", "看書"));
?
// 創建 字符串實體對象
HttpEntity httpEntity = new StringEntity(JSON.toJSONString(user));
httpPost.setEntity(httpEntity);
?
// 發送 POST 請求
httpClient.execute(httpPost);
模擬form表單數據?
// 修改 contentType
// 創建 ContentType 對象為 form 表單模式
ContentType contentType = ContentType.create("application/x-www-form-urlencoded", StandardCharsets.UTF_8);
// 添加到 HttpPost 頭中
httpPost.setHeader(HttpHeaders.CONTENT_TYPE, contentType);
創建請求數據 HttpEntity
// 方式一、自己拼接請求數據,并且創建 StringEntity 對象
String query = "name="+ URLEncoder.encode("張三", "utf-8") +"&age=20";
HttpEntity httpEntity = new StringEntity(query);
?
// 方式二、通過UrlEncodedFormEntity 創建 HttpEntity
HttpEntity httpEntity = new UrlEncodedFormEntity(
Arrays.asList(new BasicNameValuePair("name", "張三"),
new BasicNameValuePair("age", "20")),
StandardCharsets.UTF_8
);
?
// 把 HttpEntity 設置到 HttpPost 中
httpPost.setEntity(httpEntity);
?上傳
//要上傳的文件File file = new File("F:/20150703212056_Yxi4L.jpeg");?// 創建對象MultipartEntityBuilder builder = MultipartEntityBuilder.create();?// 添加二進制消息體builder.addBinaryBody("file", file);?// 也可以添加文本消息ContentType contentType = ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8);builder.addTextBody("name", "張三", contentType);?// 通過 MultipartEntityBuilder 構建消息體HttpEntity httpEntity = builder.build();HttpPost httpPost = new HttpPost("http://localhost:10010/user/upload");httpPost.setEntity(httpEntity);CloseableHttpResponse response = httpClient.execute(httpPost);// 獲取請求狀態int code = response.getCode();// 如果請求成功if(code == HttpStatus.SC_OK){LOGGER.info("響應結果為:{}", EntityUtils.toString(response.getEntity()));}
下載
// 請求下載路徑HttpGet httpGet = new HttpGet("http://localhost:10010/user/downLoad");CloseableHttpResponse response = httpClient.execute(httpGet);?// 如果請求成功if (response.getCode() == HttpStatus.SC_OK){?// 獲取下載文件的文件名,此處的 File-Name 頭信息,需要在服務端進行自定義Header header = response.getFirstHeader("File-Name");String value = header.getValue();?// 讀取數據byte[] bytes = EntityUtils.toByteArray(response.getEntity());try (OutputStream outputStream = new FileOutputStream("F:/" + value);){outputStream.write(bytes);outputStream.flush();}}
響應處理
// 轉換為字符串EntityUtils.toString(response.getEntity());?// 轉換為字節數組EntityUtils.toByteArray(response.getEntity());
?自定義響應對象
@Data@Accessors(chain = true)class Response {// 響應狀態private int code;// 響應描述private String msg;// 響應體private String body;}?// 調用 execute 時自定義 響應處理類Response execute = httpClient.execute(httpGet, response -> {return new Response().setCode(response.getCode()).setMsg(response.getReasonPhrase()).setBody(EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8));});
?會話保持
// 創建 HttpClientContext對象HttpContext httpContext = new BasicHttpContext();httpContext.setAttribute("name", "zhangsan");HttpClientContext httpClientContext = HttpClientContext.adapt(httpContext);?// 登錄httpClient.execute(new HttpPost(""), httpClientContext);?// 獲取數據httpClient.execute(new HttpGet(""), httpClientContext);
4.?OkHttp
具有低內存占有和出色的性能
引入依賴
<dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.0.0</version></dependency>
5.?HttpURLConnection
Java 自帶的一個 HTTP 客戶端工具
示例:
@Testpublic void doGet() throws IOException {String userId = "張三"; // 參數值userId = URLEncoder.encode(userId, "UTF-8"); // 對參數值進行URL編碼//步驟一:創建URL對象URL url = new URL("http://127.0.0.1:8094/masterdata/sysUser/getSysUserById?userId=" + userId);//步驟二:打開連接 HttpURLConnection繼承自URLConnection,是它的一個子類,//而HttpURLConnection專門用于處理HTTP協議的連接,如果需要處理其他協議使用通用的URLConnection。HttpURLConnection conn = (HttpURLConnection) url.openConnection();//步驟三:設置請求方式conn.setRequestMethod("GET");//步驟四:讀取響應內容BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));StringBuilder sb = new StringBuilder();String line;while ((line = reader.readLine()) != null) {sb.append(line);}reader.close();System.out.println(sb.toString());} @Testpublic void doPost() throws IOException {//創建URL對象URL url = new URL("http://127.0.0.1:8094/masterdata/sysUser/saveUser");//打開連接HttpURLConnection conn = (HttpURLConnection) url.openConnection();//設置請求方式conn.setRequestMethod("POST");// 設置請求頭conn.setRequestProperty("Content-Type", "application/json");//啟用輸出流//告訴連接對象您將使用輸出流來發送數據,這樣它會準備好接受輸出流,并將數據發送到服務器。//這是發送POST請求體數據所必需的步驟。get沒有請求體不需要conn.setDoOutput(true);//設置請求體數據Map map = new HashMap<>();map.put("name", "張三");String requestBody = JSON.toJSONString(map);//發送請求體數據try (DataOutputStream outputStream = new DataOutputStream(conn.getOutputStream())) {outputStream.write(requestBody.getBytes(StandardCharsets.UTF_8));}//讀取響應內容BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));StringBuilder sb = new StringBuilder();String line;while ((line = reader.readLine()) != null) {sb.append(line);}reader.close();System.out.println(sb.toString());}
6.?FeignClient
引入依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
在 spring boot 啟動類加上@EnableFeignClients注解
// name:指定Feign的名稱,如果使用了注冊中心,name屬性會作為微服務的名稱,用于服務發現
// url:Feign調用的跳轉路徑,可以在配置文件中設置,多用于代碼調試
@FeignClient(name = "masterdata",url = "${masterdata-service-url}")
public interface ISysUserClient {@GetMapping(value = "/masterdata/getSysUserById")public Map getSysUserById(@RequestParam("userId") String userId);
}
默認是連接超時10s,讀超時60s ,feign 集成了 ribbon 和 hystrix,feign 本身不帶超時限制,其超時是由 ribbon 和 hystrix 控制的。
## 方法一:設置在ribbon上
ribbon:OkToRetryOnAllOperations: false #對所有操作請求都進行重試,默認falseReadTimeout: 5000 #負載均衡超時時間,默認值5000ConnectTimeout: 3000 #ribbon請求連接的超時時間,默認值2000MaxAutoRetries: 0 #對當前實例的重試次數,默認0MaxAutoRetriesNextServer: 1 #對切換實例的重試次數,默認1## 方法二:設置在feign client上
feign:client:config:default:connectTimeout: 5000readTimeout: 3000
7.?AsyncHttpClient
AsyncHttpClient是一個獨立的開源庫,它不依賴于任何的框架或者技術棧
依賴:
<dependency><groupId>org.asynchttpclient</groupId><artifactId>async-http-client</artifactId><version>2.12.3</version>
</dependency>
示例:
public class TestAsyncHttpClient {@Testpublic void doGet() throws IOException {try (AsyncHttpClient client = new DefaultAsyncHttpClient();) {BoundRequestBuilder requestBuilder = client.prepareGet("http://127.0.0.1:8094/masterdata/sysUser/getSysUserById?userId=郭郭");CompletableFuture<String> future = requestBuilder.execute().toCompletableFuture().thenApply(Response::getResponseBody);//使用join等待響應完成String responseBody = future.join();System.out.println(responseBody);}}@Testpublic void doPost() throws IOException {try (AsyncHttpClient client = new DefaultAsyncHttpClient();) {BoundRequestBuilder requestBuilder = client.preparePost("http://127.0.0.1:8094/masterdata/sysUser/saveUser");//requestBody請求入參Map map = new HashMap<>();map.put("name", "郭郭");String requestBody = JSON.toJSONString(map);requestBuilder.addHeader("Content-Type", "application/json");requestBuilder.setBody(requestBody);CompletableFuture<String> future = requestBuilder.execute().toCompletableFuture().thenApply(Response::getResponseBody);//使用join等待響應完成String responseBody = future.join();System.out.println(responseBody);}}}