目录
调用示例--post请求(接口使用@RequestParam注解即以表单方式提交)
调用示例--post请求(接口使用@RequestBody注解即以json方式提交)
2.1、从HttpResponse解析出Http StatusCode,如果状态码StatusCode为null,就抛出UnknownHttpStatusCodeException异常。
2.2、如果StatusCode存在,则解析出StatusCode的series,也就是状态码段(除了2xx段,其他全是异常状态码),解析规则是StatusCode/100取整。
设置连接超时
SimpleClientHttpRequestFactory.class中默认无限制
private int connectTimeout = -1;
private int readTimeout = -1;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
return restTemplate;
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(5000);
factory.setConnectTimeout(10000);
return factory;
}
}
调用示例--get请求
@Autowired private RestTemplate restTemplate;
Map paramMap = new HashMap<String, String>(1); paramMap.put("userId", "system"); try { ResponseEntity<JSONArray> forEntity = restTemplate.getForEntity("http://192.168.3.213:32410/queryUserRoles?userId={userId}", JSONArray.class, paramMap); JSONArray routeDTOs = forEntity.getBody(); System.out.println("========================="+routeDTOs.toJSONString()); } catch (RestClientException e) { //RestClientException是HttpClientErrorException、HttpServerErrorException等的父类 e.printStackTrace(); }
调用示例--post请求(接口使用@RequestParam注解即以表单方式提交)
调用示例--post请求(接口使用@RequestBody注解即以json方式提交)
//发送Post数据并解析数据
String casServiceUrl = casClientProperties.getCasServiceUrl();
String url = casServiceUrl + "/addClient";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> request = new HttpEntity<String>(serviceInfo.toJSONString(), headers);
try {
ResponseEntity<JSONObject> responseEntity = restTemplate.postForEntity(url, request, JSONObject.class);
JSONObject body = responseEntity.getBody();
if (!body.isEmpty() && body.getInteger("code") != null) {
int code = body.getInteger("code").intValue();
if (code == 200) {
log.info("CAS client added successfully, serviceInfo:\n{}",serviceInfo.toJSONString());
} else if (code == 201) {
......
}
自定义异常处理
1、异常现象
在使用RestTemplate进行远程接口服务调用的时候,当请求的服务出现异常:超时、服务不存在等情况的时候(响应状态非200、而是400、500等HTTP状态码),就会抛出如下异常:
2、源码解析-默认实现
RestTemplate请求结果异常是可以自定义处理的。在开始进行自定义的异常处理逻辑之前,我们有必要看一下异常处理的默认实现。
ResponseErrorHandler是RestTemplate请求结果的异常处理器接口
接口的第一个方法hasError用于判断HttpResponse是否是异常响应(通过状态码)
接口的第二个方法handleError用于处理异常响应结果(非2xx状态码段)
DefaultResponseErrorHandler是ResponseErrorHandler的默认实现,所以我们就来看看DefaultResponseErrorHandler是如何来处理异常响应的?
2.1、从HttpResponse解析出Http StatusCode,如果状态码StatusCode为null,就抛出UnknownHttpStatusCodeException异常。
2.2、如果StatusCode存在,则解析出StatusCode的series,也就是状态码段(除了2xx段,其他全是异常状态码),解析规则是StatusCode/100取整。
public enum Series {
INFORMATIONAL(1), // 1xx/100
SUCCESSFUL(2), // 2xx/100
REDIRECTION(3), // 3xx/100
CLIENT_ERROR(4), // 4xx/100 ,客户端异常
SERVER_ERROR(5); // 5xx/100 ,服务端异常
......
............
}
2.3、进一步针对客户端异常和服务端异常进行处理,处理的方法是抛出HttpClientErrorException。也就是第一小节截图中出现的异常的原因,下面三个异常都是RestClientException的子类
3、RestTemplate自定义异常处理
所以我们要实现自定义异常,实现ResponseErrorHandler接口 [仿照DefaultResponseErrorHandler实现]就可以。
import com.genertech.plm.aia.login.cas.customerAuthentication.exception.MyFailedLoginException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.UnknownHttpStatusCodeException;
import java.io.IOException;
import java.nio.charset.Charset;
/**
* @author: huo.qw
* @createTime: 2023/06/27 下午 07:27
* @description: 自定义RestTemplate抛出的异常为CAS的异常,
* 解决RestTemplate抛出的异常提前被CAS源码PolicyBasedAuthenticationManager捕获的问题
* @version: v1.0
*/
@Slf4j
public class CustomerRestTemplateResponseErrorHandler implements ResponseErrorHandler {
public CustomerRestTemplateResponseErrorHandler() {
}
/**
* 判断返回结果response是否是异常结果
* 主要是去检查response 的HTTP Status
* [仿照DefaultResponseErrorHandler实现即可]
*/
public boolean hasError(ClientHttpResponse response) throws IOException {
int rawStatusCode = response.getRawStatusCode();
// 模拟失败
//rawStatusCode = 400;
HttpStatus[] var3 = HttpStatus.values();
int var4 = var3.length;
for (int var5 = 0; var5 < var4; ++var5) {
HttpStatus statusCode = var3[var5];
if (statusCode.value() == rawStatusCode) {
return this.hasError(statusCode);
}
}
return this.hasError(rawStatusCode);
}
protected boolean hasError(HttpStatus statusCode) {
return statusCode.is4xxClientError() || statusCode.is5xxServerError();
}
protected boolean hasError(int unknownStatusCode) {
int seriesCode = unknownStatusCode / 100;
return seriesCode == HttpStatus.Series.CLIENT_ERROR.value() || seriesCode == HttpStatus.Series.SERVER_ERROR.value();
}
/*//默认的
@Override
public void handleError(ClientHttpResponse response) throws IOException {
HttpStatus statusCode = this.getHttpStatusCode(response);
switch(statusCode.series()) {
case CLIENT_ERROR:
throw new HttpClientErrorException(statusCode, response.getStatusText(), response.getHeaders(), this.getResponseBody(response), this.getCharset(response));
case SERVER_ERROR:
throw new HttpServerErrorException(statusCode, response.getStatusText(), response.getHeaders(), this.getResponseBody(response), this.getCharset(response));
default:
throw new UnknownHttpStatusCodeException(statusCode.value(), response.getStatusText(), response.getHeaders(), this.getResponseBody(response), this.getCharset(response));
}
}*/
//改造的
@Override
public void handleError(ClientHttpResponse response) throws IOException {
HttpStatus statusCode = this.getHttpStatusCode(response);
switch (statusCode.series()) {//HttpStatus.Series.CLIENT_ERROR
case CLIENT_ERROR:
HttpClientErrorException httpClientErrorException = new HttpClientErrorException(statusCode, response.getStatusText(), response.getHeaders(), this.getResponseBody(response), this.getCharset(response));
log.error("RestTemplate RPC CLIENT_ERROR:\n", httpClientErrorException);
// 抛出自定义的可以返回给前端信息的异常
throw new MyFailedLoginException("RPC CLIENT_ERROR");
case SERVER_ERROR:
HttpServerErrorException httpServerErrorException = new HttpServerErrorException(statusCode, response.getStatusText(), response.getHeaders(), this.getResponseBody(response), this.getCharset(response));
log.error("RestTemplate RPC SERVER_ERROR:\n", httpServerErrorException);
// 抛出自定义的可以返回给前端信息的异常
throw new MyFailedLoginException("RPC SERVER_ERROR");
default:
UnknownHttpStatusCodeException e = new UnknownHttpStatusCodeException(statusCode.value(), response.getStatusText(), response.getHeaders(), this.getResponseBody(response), this.getCharset(response));
log.error("RestTemplate RPC UnknownHttpStatusCodeException:\n", e);
// 抛出自定义的可以返回给前端信息的异常
throw new MyFailedLoginException("RPC UnknownHttpStatusCode");
}
}
protected HttpStatus getHttpStatusCode(ClientHttpResponse response) throws IOException {
try {
return response.getStatusCode();
} catch (IllegalArgumentException var3) {
throw new UnknownHttpStatusCodeException(response.getRawStatusCode(), response.getStatusText(), response.getHeaders(), this.getResponseBody(response), this.getCharset(response));
}
}
protected byte[] getResponseBody(ClientHttpResponse response) {
try {
return FileCopyUtils.copyToByteArray(response.getBody());
} catch (IOException var3) {
return new byte[0];
}
}
protected Charset getCharset(ClientHttpResponse response) {
HttpHeaders headers = response.getHeaders();
MediaType contentType = headers.getContentType();
return contentType != null ? contentType.getCharset() : null;
}
}
将MyRestErrorHandler 在RestTemplate实例化的时候进行注册即可