Comment utiliser les services Java RestTemplate et 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; } }
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Guide de la racine carrée en Java. Nous discutons ici du fonctionnement de Square Root en Java avec un exemple et son implémentation de code respectivement.

Guide du nombre parfait en Java. Nous discutons ici de la définition, comment vérifier le nombre parfait en Java ?, des exemples d'implémentation de code.

Guide du générateur de nombres aléatoires en Java. Nous discutons ici des fonctions en Java avec des exemples et de deux générateurs différents avec d'autres exemples.

Guide de Weka en Java. Nous discutons ici de l'introduction, de la façon d'utiliser Weka Java, du type de plate-forme et des avantages avec des exemples.

Guide du nombre de Smith en Java. Nous discutons ici de la définition, comment vérifier le numéro Smith en Java ? exemple avec implémentation de code.

Dans cet article, nous avons conservé les questions d'entretien Java Spring les plus posées avec leurs réponses détaillées. Pour que vous puissiez réussir l'interview.

Java 8 présente l'API Stream, fournissant un moyen puissant et expressif de traiter les collections de données. Cependant, une question courante lors de l'utilisation du flux est: comment se casser ou revenir d'une opération FOREAK? Les boucles traditionnelles permettent une interruption ou un retour précoce, mais la méthode Foreach de Stream ne prend pas directement en charge cette méthode. Cet article expliquera les raisons et explorera des méthodes alternatives pour la mise en œuvre de terminaison prématurée dans les systèmes de traitement de flux. Lire plus approfondie: Améliorations de l'API Java Stream Comprendre le flux Forach La méthode foreach est une opération terminale qui effectue une opération sur chaque élément du flux. Son intention de conception est

Guide de TimeStamp to Date en Java. Ici, nous discutons également de l'introduction et de la façon de convertir l'horodatage en date en Java avec des exemples.
