北京到广州列车时刻表,公众号排名优化,网站建设需不需要招标,电子商务网站建设的规划和实施日常工作中肯定会遇到服务之间的调用#xff0c;尤其是现在都是微服务的架构#xff0c;所以总结一下restTemplate的最常用的用法以及自己踩过的坑。 restTemplate的使用 restTemplate底层调用的是Execute方法#xff0c;而Execute底层调用的是doExecute#xff0c;它是基于…日常工作中肯定会遇到服务之间的调用尤其是现在都是微服务的架构所以总结一下restTemplate的最常用的用法以及自己踩过的坑。 restTemplate的使用 restTemplate底层调用的是Execute方法而Execute底层调用的是doExecute它是基于http协议的底层还是httpClient 的使用。 /*** Execute the given method on the provided URI.* pThe {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 ResponseExtractorT 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);HttpEntityYourRequest requestEntity new HttpEntity(request, headers);ResponseEntityYourResponse 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.* pThis 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