Cara menggunakan perkhidmatan Java RestTemplate dan HttpClient
概述
常见的远程调用方式有以下2种:
RPC: Remote Produce Call远程过程调用,类似的还有RMI(remote method invoke)。自定义数据格式,基于原生TCP通信,速度快,效率高。早期的webservice,现在热门的dubbo,都是RPC的典型代表。
Http: http其实是一种网络传输协议,基于TCP,规定了数据传输的格式。 现在客户端浏览器与服务端通信基本都是采用Http协议,也可以用来进行远程服务调用。缺点是消息封装臃肿,优势是对服务的提供和调用方没有任何技术限定,自由灵活,更符合微服务理念。现在热门的Rest风格,就可以通过http协议来实现。
如果项目全部采用 Java技术栈,那么使用Dubbo作为微服务架构是一个不错的选择。
如果项目的技术栈多样化,主要采用了Spring和SpringBoot框架,那么SpringCloud搭建微服务是不二之选,使用Http方式来实现服务间调用。
java开发中,使用http连接,访问第三方网络接口,通常使用的连接工具为RestTemplate、HttpClient和OKHttp。
RestTemplate
概述及依赖
HttpClient和OKHttp两种连接工具,使用起来比较复杂,如果使用spring框架,可以使用restTemplate来进行http连接请求。
restTemplate默认的连接方式是java中的HttpConnection,可以使用ClientHttpRequestFactory指定不同的HTTP连接方式。
依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.2.2.RELEASE</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.7</version> </dependency>
配置类
基础配置
@Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate(ClientHttpRequestFactory factory) { return new RestTemplate(factory); } @Bean public ClientHttpRequestFactory simpleClientHttpRequestFactory() { SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); factory.setReadTimeout(150 * 1000); // ms factory.setConnectTimeout(150 * 1000); // ms return factory; } }
进阶配置
import org.apache.http.client.HttpClient; import org.apache.http.conn.HttpClientConnectionManager; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; @Configuration public class RestTemplateConfig { /** * http连接管理器 */ @Bean public HttpClientConnectionManager poolingHttpClientConnectionManager() { /*// 注册http和https请求 Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) .register("https", SSLConnectionSocketFactory.getSocketFactory()) .build(); PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(registry);*/ PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(); // 最大连接数 poolingHttpClientConnectionManager.setMaxTotal(500); // 同路由并发数(每个主机的并发) poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100); return poolingHttpClientConnectionManager; } /** * HttpClient * @param poolingHttpClientConnectionManager */ @Bean public HttpClient httpClient(HttpClientConnectionManager poolingHttpClientConnectionManager) { HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); // 设置http连接管理器 httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager); /*// 设置重试次数,默认是3次,没有开启 httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true));*/ // 设置默认请求头 /*List<Header> headers = new ArrayList<>(); headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36")); headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate")); headers.add(new BasicHeader("Accept-Language", "zh-CN")); headers.add(new BasicHeader("Connection", "Keep-Alive")); headers.add(new BasicHeader("Content-type", "application/json;charset=UTF-8")); httpClientBuilder.setDefaultHeaders(headers);*/ return httpClientBuilder.build(); } /** * 请求连接池配置 * @param httpClient */ @Bean public ClientHttpRequestFactory clientHttpRequestFactory(HttpClient httpClient) { HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(); // httpClient创建器 clientHttpRequestFactory.setHttpClient(httpClient); // 连接超时时间/毫秒(连接上服务器(握手成功)的时间,超出抛出connect timeout) clientHttpRequestFactory.setConnectTimeout(5 * 1000); // 数据读取超时时间(socketTimeout)/毫秒(服务器返回数据(response)的时间,超过抛出read timeout) clientHttpRequestFactory.setReadTimeout(10 * 1000); // 从连接池获取请求连接的超时时间,不宜过长,必须设置/毫秒(超时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool) clientHttpRequestFactory.setConnectionRequestTimeout(10 * 1000); return clientHttpRequestFactory; } /** * rest模板 */ @Bean public RestTemplate restTemplate(ClientHttpRequestFactory clientHttpRequestFactory) { // 配置请求工厂 return new RestTemplate(clientHttpRequestFactory); } }
使用
实体类
@Data @Builder @NoArgsConstrutor @AllArgsConstrutor public class BaseResponse<TempUser> implements Serializable { private static final long serialVersionUID = 1L; private String responseCode; private String responseMessage; private List<TempUser> responseData; }
@Data @Builder @NoArgsConstrutor @AllArgsConstrutor public class TempUser implements Serializable { private static final long serialVersionUID = 1L; private String userName; private Integer age; }
GET请求
普通访问
BaseResponse result = restTemplate.getForObject( "http://localhost:8080/cs-admin/rest/getUser?userName=张三&age=18", BaseResponse.class);
返回HTTP状态
ResponseEntity<BaseResponse> responseEntity = restTemplate.getForEntity( "http://localhost:8080/cs-admin/rest/getUser?userName=张三&age=18", TempUser.class); // 获取状态对象 HttpStatus httpStatus = responseEntity.getStatusCode(); // 获取状态码 int statusCodeValue = responseEntity.getStatusCodeValue(); // 获取headers HttpHeaders httpHeaders = responseEntity.getHeaders(); // 获取body BaseResponse result = responseEntity.getBody();
映射请求参数
Map<String, Object> paramMap = new HashMap<>(); paramMap.put("userName", "张三"); paramMap.put("age", 18); BaseResponse result = restTemplate.getForObject( "http://localhost:8080/cs-admin/rest/getUser?userName={userName}&age={age}", BaseResponse.class, paramMap);
POST请求
普通访问接口
TempUser param = new TempUser(); param.setUserName("张三"); param.setAge(18); BaseResponse result = restTemplate.postForObject("http://localhost:8080/cs-admin/rest/getPostUser", param, BaseResponse.class);
带HEAD访问接口
// 请求头信息 HttpHeaders headers = new HttpHeaders(); //headers.setContentType(MediaType.valueOf("application/json;charset=UTF-8")); headers.setContentType(MediaType.APPLICATION_JSON_UTF8); //headers.add("headParam1", "headParamValue"); // 请求体内容 TempUser param = new TempUser(); param.setUserName("张三"); param.setAge(18); // 组装请求信息 HttpEntity<TempUser> httpEntity=new HttpEntity<>(param, headers); BaseResponse result = restTemplate.postForObject("http://localhost:8080/cs-admin/rest/getPostUser", httpEntity, BaseResponse.class);
无请求体的访问:仅method为post,传参方式仍然为get的param方式
Map<String, Object> paramMap = new HashMap<>(); paramMap.put("userName", "张三"); paramMap.put("age", 18); BaseResponse result = restTemplate.postForObject( "http://localhost:8080/cs-admin/rest/getPostUserNoBody?userName={userName}&age={age}", null, BaseResponse.class, paramMap); System.out.println(result);
上传文件
后台接口代码:
@RequestMapping("uploadFile") public TempUser uploadFile(HttpServletRequest request, TempUser form) { MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request; //获取文件信息 MultipartFile multipartFile = multipartHttpServletRequest.getFile("file"); TempUser tempUser = new TempUser(); if (multipartFile != null) { tempUser.setUserName(form.getUserName() + " " + multipartFile.getOriginalFilename()); } if(form!=null){ tempUser.setAge(form.getAge()); } return tempUser; }
访问方式:
// 文件 FileSystemResource file=new FileSystemResource("D:\\Elasticsearch权威指南(中文版).pdf"); // 设置请求内容 MultiValueMap<String, Object> param=new LinkedMultiValueMap<>(); param.add("file", file); // 其他参数 param.add("userName", "张三"); param.add("age", 18); // 组装请求信息 HttpEntity<MultiValueMap<String, Object>> httpEntity=new HttpEntity<>(param); // 发送请求 TempUser result = restTemplate.postForObject("http://localhost:8080/cs-admin/rest/uploadFile", httpEntity, TempUser.class);
HttpClient
概述
HttpClient 通过连接池创建连接:
管理连接的基本单位是Route(路由),每个路由上都会维护一定数量的HTTP连接
每次调用后必须执行 releaseConnection
路由可以理解为客户端机器到目标机器的一条线路
如果不给 httpclient配置指定的连接管理器,httpclient会自动使用PoolingHttpClientConnectionManager作为连接管理器。
PoolingHttpClientConnectionManager默认的maxConnPerRoute和maxConnTotal分别是是2和20。也就是对于每个服务器最多只会维护2个连接,看起来有点少。所以,在日常使用时我们尽量使用自己配置的连接管理器比较好。
连接池:
连接池技术作为创建和管理连接的缓冲池技术。
连接池管理的对象是长连接
有长连接的优势
**长连接:**是指客户端与服务器端一旦建立连接以后,可以进行多次数据传输而不需重新建立连接,
优势:
省去了每次数据传输连接建立的时间开销
资源的访问控制
**短连接:**每次数据传输都需要客户端和服务器端建立一次连接
使用
使用HttpClient
发送请求、接收响应很简单,一般需要如下几步即可:
创建
HttpClient
对象创建请求方法的实例,并指定请求
URL
。如果需要发送GET
请求,创建HttpGet
对象;如果需要发送POST
请求,创建HttpPost
对象。如果需要发送请求参数,可调用
HttpGet、HttpPost
共同的setParams(HetpParams params)
方法来添加请求参数;对于HttpPost
对象而言,也可调用setEntity(HttpEntity entity)
方法来设置请求参数,参数则必须用NameValuePair[]
数组存储调用
HttpClient
对象的execute(HttpUriRequest request)
发送请求,该方法返回一个HttpResponse
调用
HttpResponse的getAllHeaders()
、getHeaders(String name)
等方法可获取服务器的响应头;调用HttpResponse
的getEntity()
方法可获取HttpEntity
对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容释放连接。无论执行方法是否成功,都必须释放连接
依赖:
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.2</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient-cache</artifactId> <version>4.5.2</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpmime</artifactId> <version>4.5.2</version> </dependency>
java工具类
import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.http.Consts; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import java.net.URI; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * HttpClient 工具类 */ @Slf4j public class HttpClientUtil { public static final String APPLICATION_JSON_VALUE = "application/json"; private static final Logger logger = log; private static final Integer CONN_TIME_OUT = 3000;// 超时时间豪秒 private static final Integer SOCKET_TIME_OUT = 10000; /** 每个路由的最大请求数,默认2 */ private static final Integer DEFAULT_MAX_PER_ROUTE = 40; /** 最大连接数,默认20 */ private static final Integer MAX_TOTAL = 400; private static HttpClient httpClient; static { // 请求配置 RequestConfig requestConfig = RequestConfig.custom() .setConnectTimeout(CONN_TIME_OUT) .setConnectionRequestTimeout(CONN_TIME_OUT) .setSocketTimeout(SOCKET_TIME_OUT) .build(); // 管理 http连接池 PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); cm.setDefaultMaxPerRoute(DEFAULT_MAX_PER_ROUTE); cm.setMaxTotal(MAX_TOTAL); httpClient = HttpClients.custom() .setConnectionManager(cm) .setDefaultRequestConfig(requestConfig) .build(); } /** * Get请求 */ public static String requestGet(String url, Map<String, String> paramsMap) throws Exception { logger.info("GET request url:{} params:{}", url, paramsMap); Long start = System.currentTimeMillis(); List<NameValuePair> params = initParams(paramsMap); // Get请求 HttpGet httpGet = new HttpGet(url); try { // 设置参数 String str = EntityUtils.toString(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8)); String uriStr = StringUtils.isEmpty(str) ? httpGet.getURI().toString() : httpGet.getURI().toString() + "?" + str; httpGet.setURI(new URI(uriStr)); // 发送请求 HttpResponse response = httpClient.execute(httpGet); logger.info("GET request url:{} response:{} time:{}", url, response, System.currentTimeMillis() - start); // 获取返回数据 return getSuccessRetFromResp(response, url, JSON.toJSONString(paramsMap)); } finally { // 必须释放连接,不然连接用完后会阻塞 httpGet.releaseConnection(); } } /** * Post请求,Map格式数据 */ public static String requestPost(String url, Map<String, String> paramsMap) throws Exception { logger.info("POST request url:{} params:{}", url, paramsMap); Long start = System.currentTimeMillis(); List<NameValuePair> params = initParams(paramsMap); HttpPost httpPost = new HttpPost(url); try { httpPost.setEntity(new UrlEncodedFormEntity(params, Consts.UTF_8)); HttpResponse response = httpClient.execute(httpPost); logger.info("POST request url:{} response:{} time:{}", url, response, System.currentTimeMillis() - start); String retStr = getSuccessRetFromResp(response, url, JSON.toJSONString(paramsMap)); return retStr; } finally { httpPost.releaseConnection(); } } /** * Post请求,json格式数据 * */ public static String requestPostJsonStr(String url, String json) throws Exception { logger.info("POST request url:{} params:{}", url, json); long start = System.currentTimeMillis(); HttpPost httpPost = new HttpPost(url); try { StringEntity entity = new StringEntity(json, Consts.UTF_8); entity.setContentType(APPLICATION_JSON_VALUE); httpPost.setEntity(entity); HttpResponse response = httpClient.execute(httpPost); logger.info("POST request url:{} response:{} time:{}", url, response, System.currentTimeMillis() - start); return getSuccessRetFromResp(response, url, json); } finally { // 资源释放 httpPost.releaseConnection(); } } /** * post Object格式数据 */ public static String requestPostJson(String url, Object obj) throws Exception { String params = JSON.toJSONString(obj); return requestPostJsonStr(url, params); } private static String getSuccessRetFromResp(HttpResponse response, String url, String params) throws Exception { String retStr = ""; // 检验状态码,如果成功接收数据 int code = response.getStatusLine().getStatusCode(); if (code == 200) { retStr = EntityUtils.toString(response.getEntity(), Consts.UTF_8); } else { throw new RuntimeException(String.format("Http request error:%s, url:%s, params:%s", response, url, params)); } logger.info("Http request retStr:{}. url:{}", retStr, url); return retStr; } private static List<NameValuePair> initParams(Map<String, String> paramsMap) { List<NameValuePair> params = new ArrayList<NameValuePair>(); if (paramsMap == null) return params; for (Map.Entry<String, String> entry : paramsMap.entrySet()) { params.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } return params; } }
Atas ialah kandungan terperinci Cara menggunakan perkhidmatan Java RestTemplate dan HttpClient. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas



Panduan Nombor Sempurna di Jawa. Di sini kita membincangkan Definisi, Bagaimana untuk menyemak nombor Perfect dalam Java?, contoh dengan pelaksanaan kod.

Panduan untuk Weka di Jawa. Di sini kita membincangkan Pengenalan, cara menggunakan weka java, jenis platform, dan kelebihan dengan contoh.

Panduan untuk Nombor Smith di Jawa. Di sini kita membincangkan Definisi, Bagaimana untuk menyemak nombor smith di Jawa? contoh dengan pelaksanaan kod.

Dalam artikel ini, kami telah menyimpan Soalan Temuduga Spring Java yang paling banyak ditanya dengan jawapan terperinci mereka. Supaya anda boleh memecahkan temuduga.

Java 8 memperkenalkan API Stream, menyediakan cara yang kuat dan ekspresif untuk memproses koleksi data. Walau bagaimanapun, soalan biasa apabila menggunakan aliran adalah: bagaimana untuk memecahkan atau kembali dari operasi foreach? Gelung tradisional membolehkan gangguan awal atau pulangan, tetapi kaedah Foreach Stream tidak menyokong secara langsung kaedah ini. Artikel ini akan menerangkan sebab -sebab dan meneroka kaedah alternatif untuk melaksanakan penamatan pramatang dalam sistem pemprosesan aliran. Bacaan Lanjut: Penambahbaikan API Java Stream Memahami aliran aliran Kaedah Foreach adalah operasi terminal yang melakukan satu operasi pada setiap elemen dalam aliran. Niat reka bentuknya adalah

Panduan untuk TimeStamp to Date di Java. Di sini kita juga membincangkan pengenalan dan cara menukar cap waktu kepada tarikh dalam java bersama-sama dengan contoh.

Kapsul adalah angka geometri tiga dimensi, terdiri daripada silinder dan hemisfera di kedua-dua hujungnya. Jumlah kapsul boleh dikira dengan menambahkan isipadu silinder dan jumlah hemisfera di kedua -dua hujungnya. Tutorial ini akan membincangkan cara mengira jumlah kapsul yang diberikan dalam Java menggunakan kaedah yang berbeza. Formula volum kapsul Formula untuk jumlah kapsul adalah seperti berikut: Kelantangan kapsul = isipadu isipadu silinder Dua jumlah hemisfera dalam, R: Radius hemisfera. H: Ketinggian silinder (tidak termasuk hemisfera). Contoh 1 masukkan Jejari = 5 unit Ketinggian = 10 unit Output Jilid = 1570.8 Unit padu menjelaskan Kirakan kelantangan menggunakan formula: Kelantangan = π × r2 × h (4

Spring Boot memudahkan penciptaan aplikasi Java yang mantap, berskala, dan siap pengeluaran, merevolusi pembangunan Java. Pendekatan "Konvensyen Lebih Konfigurasi", yang wujud pada ekosistem musim bunga, meminimumkan persediaan manual, Allo
