restTemplate使用和踩坑总结

日常工作中肯定会遇到服务之间的调用,尤其是现在都是微服务的架构,所以总结一下restTemplate的最常用的用法以及自己踩过的坑。

restTemplate的使用

restTemplate底层调用的是Execute方法,而Execute底层调用的是doExecute,它是基于http协议的,底层还是httpClient 的使用。

/*** Execute the given method on the provided URI.* <p>The {@link ClientHttpRequest} is processed using the {@link RequestCallback};* the response with the {@link ResponseExtractor}.* @param url the fully-expanded URL to connect to* @param method the HTTP method to execute (GET, POST, etc.)* @param requestCallback object that prepares the request (can be {@code null})* @param responseExtractor object that extracts the return value from the response (can be {@code null})* @return an arbitrary object, as returned by the {@link ResponseExtractor}*/@Nullableprotected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback,@Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {Assert.notNull(url, "URI is required");Assert.notNull(method, "HttpMethod is required");ClientHttpResponse response = null;try {ClientHttpRequest request = createRequest(url, method);if (requestCallback != null) {requestCallback.doWithRequest(request);}response = request.execute();handleResponse(url, method, response);return (responseExtractor != null ? responseExtractor.extractData(response) : null);}catch (IOException ex) {String resource = url.toString();String query = url.getRawQuery();resource = (query != null ? resource.substring(0, resource.indexOf('?')) : resource);throw new ResourceAccessException("I/O error on " + method.name() +" request for \"" + resource + "\": " + ex.getMessage(), ex);}finally {if (response != null) {response.close();}}}
复制代码

我们一般都是用的restTepmlate的exchange方法,这个方法比较灵活,可以接受可变参数,重载方法也有很多。 当然 restTemplate还有其他很多方法,而且遵循restFul风格,像PUT POST GET PATCH DELETE 等都有对应的方法,按需使用。这里就不贴源码了。

然后就贴一个使用案例代码上来:

public YourResponse sampleRestTepmlate (YourRequest request) throws Exception {UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(this.serviceUrl);builder.path("urlpath");log.info("url : {}, request : {}", builder.toUriString(), JsonUtils.toJson(request));HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_JSON);headers.set("headername","headervalue");headers.add("anotherway", "value");HttpEntity<YourRequest> requestEntity = new HttpEntity<>(request, headers);ResponseEntity<YourResponse> responseEntity = null;try {responseEntity = restTemplate.exchange(builder.toUriString(), HttpMethod.POST, requestEntity,YourResponse.class);return responseEntity.getBody();} catch (Exception e) {log.error("exception:{}",e.getMessage());}}
复制代码

踩坑大道

这里就要说一下我遇到的坑了。 在使用restTemplate的时候,当你的call没有成功返回200的时候,比如返回400 500之类的,restTemplate里面有一个DefaultResponseErrorHandler,他会自动拦截住这些httpstatus 为400 500的response然后给你抛出一个异常。这就意味着,当你也想拿到带有错误信息的response的时候,他不会给你!它会给你抛出exception并且只是给你返回一个简单的类似500 Internal error! WTF!

贴上这段坑爹的代码:

/*** Handle the error in the given response with the given resolved status code.* <p>This default implementation throws a {@link HttpClientErrorException} if the response status code* is {@link org.springframework.http.HttpStatus.Series#CLIENT_ERROR}, a {@link HttpServerErrorException}* if it is {@link org.springframework.http.HttpStatus.Series#SERVER_ERROR},* and a {@link RestClientException} in other cases.* @since 5.0*/protected void handleError(ClientHttpResponse response, HttpStatus statusCode) throws IOException {switch (statusCode.series()) {case CLIENT_ERROR:throw new HttpClientErrorException(statusCode, response.getStatusText(),response.getHeaders(), getResponseBody(response), getCharset(response));case SERVER_ERROR:throw new HttpServerErrorException(statusCode, response.getStatusText(),response.getHeaders(), getResponseBody(response), getCharset(response));default:throw new UnknownHttpStatusCodeException(statusCode.value(), response.getStatusText(),response.getHeaders(), getResponseBody(response), getCharset(response));}}
复制代码

脱坑之计

遇到了坑就不要害怕,这个问题可以这么解决:

1.不用restTemplate去请求,可以采用httpClient底层去实现

2.重写handleError方法,自定义ErrorHandle继承DefaultResponseErrorHandler

在已经写完实现之后,我选择方式2 : )

@Builder
@Slf4j
public class MyErrorHandle extends DefaultResponseErrorHandler {@Overridepublic void handleError(ClientHttpResponse response, HttpStatus statusCode) throws IOException {int status = statusCode.value();if (status == 200 || status == 400 || status == 500) {//do what u want to do} else {super.handleError(response,statusCode);}}}复制代码

然后在初始化restTemplate的时候调用setErrorHandle方法就可以了。

restTemplate.setErrorHandler(YourErrorHandle).
复制代码

至于方式一这里不提了。

导入证书

有的时候当我们调用对方的server时,基于https 的协议是需要导入证书的,那我们该怎么把证书融入到restTemplate中呢?(又一个坑)

@Beanpublic RestTemplate buildRestTemplateWithinSSl(@Value("${service.connectTimeout}") int connectTimeout,@Value("${service.readTimeout}") int readTimeout,@Value("${service.sslFilePath}") String filePath,@Value("${service.sslpassword}") String sslPassword) throws Exception{RestTemplate template = restTemplateBuilder.setConnectTimeout(connectTimeout).setReadTimeout(readTimeout).build();String workingDirectory = BeanUtility.getWorkingDirectory();SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(new File(workingDirectory + "/" + filePath), sslPassword.toCharArray()).build();SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory).build();HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);template.setRequestFactory(factory);return template;}
复制代码

相当于重新给RequestFactory值,构造一个已经带有ssl证书的factory给他。

这里注意两个地方:

SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
复制代码

这里有个参数是NoopHostnameVerifier.INSTANCE, 这里是可以无视ip的,也就是ip或者域名形式都可以。 (适用于对方给我提供证书和 ip地址,试了半天死活不通的情况。。)

第二个就是一个工具类的使用,我相信很多时候new file的时候很容易被路径绕晕。

String workingDirectory = BeanUtility.getWorkingDirectory();
复制代码

这个工具类获得的路径不用你去担心,只要你的jks文件和你的jar包同级就行。管他什么环境什么路径,很方便。

贴上地址: github.com/AnsonCong/A…

本地调试证书导入jdk就行。

记录下导入证书的方法:

keytool -import -alias {别名} -file {路径\证书名}.cer -keystore "{jdk路径\jre\lib\security\cacerts}" -storepass {password} -trustcacerts
复制代码

删除证书:

keytool -delete -alias {别名}  -keystore "C:\Program Files\Java\jdk1.7.0_25\jre\lib\security\cacerts" -storepass {password}
复制代码

查看所有安装证书列表

keytool -list -v  -keystore "C:\Users\1580977\Downloads\jdk1.8.0_101\jre\lib\security\cacerts" -storepass {password} >> C:\Desktop\abcd.txt
复制代码

生成jks文件 (没有默认生存,有就导入)

keytool -import -alias {别名} -file {证书名}.cer -keystore {命名}.jks
复制代码

最后

RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。

更多restTemplate详细资料,可以参考: juejin.im/post/5b88b1… www.zifangsky.cn/1221.html

或者其他掘金好文。

转载于:https://juejin.im/post/5cb96e84e51d456e5d3dac38

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/387822.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

常见编码总结

本文总结自&#xff1a;https://blog.csdn.net/zmx729618/article/details/51821024 1. ISO 8859-1 字节数&#xff1a;1 范围&#xff1a;0-255&#xff08;编码范围是0x00-0xFF&#xff09;&#xff0c;其中0x00-0x7F之间完全和ASCII一致&#xff08;ASCII是7位编码&#xff…

启动一个Java进程

windows版本 startup.bat -------------------------------------------------------- rem --------------------------------------------------------------------------- rem Start SMS Server by zhangjin rem --------------------------------------------------------…

Flask框架从入门到精通之参数配置(二)

知识点&#xff1a; 1、参数配置 一、概况 上一篇我们已经把Flask第一个程序运行起来了&#xff0c;那么这一篇主要讲一下Flask参数的配置。 二、配置参数 Flask参数配置方式有很多种&#xff0c;每一种都可以达到结果&#xff0c;在合适的场景选择合适的配置方式。 配置文件 在…

BP神经网络python简单实现

BP神经网络的原理在网上有很详细的说明&#xff0c;这里就不打算细说&#xff0c;这篇文章主要简单的方式设计及实现BP神经网络&#xff0c;并简单测试下在恒等计算&#xff08;编码&#xff09;作测试。 BP神经网络模型图如下 BP神经网络基本思想 BP神经网络学习过程由信息的…

golang的reflection(转)(一)

2019独角兽企业重金招聘Python工程师标准>>> 反射reflection 可以大大提高程序的灵活性&#xff0c;使得interface{}有更大的发挥余地反射可以使用TypeOf和ValueOf函数从接口中获取目标对象信息反射会将匿名字段作为独立字段&#xff08;匿名字段的本质&#xff09;…

idea教程--Maven 骨架介绍

简单的说&#xff0c;Archetype是Maven工程的模板工具包。一个Archetype定义了要做的相同类型事情的初始样式或模型。这个名称给我们提供来了一个一致的生成Maven工程的方式。Archetype会帮助作者给用户创建Maven工程模板&#xff0c;并给用户提供生成相关工程模板版本的参数化…

datatables.js 简单使用--多选框和服务器端分页

说明&#xff1a;datatables是一款jQuery表格插件。感觉EasyUI的datagrid更易用 内容&#xff1a;多选框和服务器端分页 缘由&#xff1a;写这篇博客的原因是datatables的文档写的不怎么样&#xff0c;找东西很麻烦 环境&#xff1a;asp.net mvc , vs2015sqlserver2012 显示效…

python异常(高级) Exception

异常(高级) Exception 异常回顾:     try-except 语句 捕获(接收)异常通知,把异常流程变为正常流程     try-finally 语句 执行必须要执行的语句.     raise 语句 发送异常通知,同时进入异常流程     assert 语句 发送AssertionError异常     with 语句 wi…

反射赋值

目前例子为NPOI Excel导入 入库时调用 var file file1.PostedFile.InputStream;var fileExt System.IO.Path.GetExtension(file1.FileName);IWorkbook workbook;if (fileExt ".xlsx")workbook new XSSFWorkbook(file);elseworkbook new HSSFWorkbook(file);DB.D…

基于PCA(主成分分析)的人脸识别

代码下载&#xff1a;基于PCA&#xff08;主成分分析&#xff09;的人脸识别 人脸识别是一个有监督学习过程&#xff0c;首先利用训练集构造一个人脸模型&#xff0c;然后将测试集与训练集进行匹配&#xff0c;找到与之对应的训练集头像。最容易的方式是直接利用欧式距离计算测…

从BMW Vision iNEXT 看宝马如何进军自动驾驶

安全很重要&#xff0c;空间也要很大&#xff0c;砍掉大量物理按键&#xff0c;内饰材料要环保&#xff0c;还要提供自动和主动两套驾驶方案。这些描述仅是BMW Vision iNEXT&#xff08;下称Vision iNEXT&#xff09;概念车的设计之冰山一角。 一款概念车当然无法完全代表未来…

CSS浮动(二)---Float

重新认识float 2.1. 误解和“误用” 既然提到“误用”&#xff0c;各位看官就此想想&#xff0c;自己平日是怎么使用float的&#xff1f;另外&#xff0c;既然“误用”加了引号&#xff0c;就说明这样的使用并不是真正的误用&#xff0c;而是误打误撞使用之后&#xff0c;带…

Hadoop0.20.2版本在Ubuntu下安装和配置

1、安装JDK   &#xff08;1&#xff09;下载安装JDK&#xff1a;确保计算机联网之后命令行输入下面命令安装JDK   sudo apt-get install sun-java6-jdk   &#xff08;2&#xff09;配置计算机Java环境&#xff1a;打开/etc/profile&#xff0c;在文件最后输入下面内容 …

云原生生态周报 Vol. 2

业界要闻 Kubernetes External Secrets 近日&#xff0c;世界上最大的域名托管公司 Godaddy公司&#xff0c;正式宣布并详细解读了其开源的K8s外部 Secrets 管理项目&#xff1a; Kubernetes External Secrets&#xff0c;简称KES。这个项目定义了ExternalSecrets API&#xff…

centos 7新机使用前操作

关闭防火墙 systemctl stop firewalld&#xff08;停服务&#xff09; systemctl status firewalld&#xff08;看状态&#xff09; systemctl disable firewalld.service &#xff08;永久关闭&#xff09; selinux getenforce&#xff08;查状态&#xff09; vi /etc/selinux…

ubuntu10.04+hadoop0.20.2平台配置(完全分布式模式)

配置环境及有关工具&#xff1a;ubuntu10.04 、hadoop0.20.2 、 jdk1.6.0_29 我们的机器有三台&#xff0c;一台当作namenode、两台当作datanode&#xff1a; namenode&#xff1a;IP:192.168.0.25、机器名&#xff1a;kiddenzj &#xff08;这里的机器名要注意&#xff1a;机…

成佛、远不止渡沧海

地之及东南&#xff0c;有一海&#xff0c;称为“沧海”。沧海对面&#xff0c;就是仙家佛地。凡是能渡过沧海到达彼岸的人&#xff0c;就能立地成佛&#xff0c;修成正果。 于是&#xff0c;许许多多的人千里迢迢赶来&#xff0c;或乘帆船&#xff0c;或乘木筏&#xff0c;纷纷…

软件架构演进

传统架构到分布式架构详解 软件架构演进软件架构的发展经历了从单体架构、垂直架构、SOA架构到微服务架构的过程&#xff0c;博客里写到了这四种架构的特点以及优缺点分析&#xff0c;个人学习之用&#xff0c;仅供参考&#xff01; 1.1.1 单体架构 特点&#xff1a;1、所有的…

hadoop0.20.0第一个例子

这是Hadoop学习全程记录第2篇&#xff0c;在这篇里我将介绍一下如何在Eclipse下写第一个MapReduce程序。 新说明一下我的开发环境&#xff1a; 操作系统&#xff1a;在windows下使用wubi安装了ubuntu 10.10 hadoop版本&#xff1a;hadoop-0.20.2.tar.gz Eclipse版本&…

IDEA 修改JavaWeb的访问路径

问题描述 对于我这个刚刚使用IDEA不久的新手来说&#xff0c;能够正常运行就不错了,不过到了后面&#xff0c;可能会觉得IDEA给你分配的默认访问路径很不顺手&#xff0c;比如访问的时候需要通过: http://localhost:8080/web_war_exploded/ 来访问&#xff0c;对于web_w…