基础
推荐使用RestTemplateBuilder构建RestTemplate
我们看下RestTemplate的基础成员变量
- requestFactory: ClientHttpRequestFactory
- defaultUriVariables: Map<String, ?>
- uriTemplateHandler: UriTemplateHandler
- interceptors: List<ClientHttpRequestInterceptor>
- messageConverters: List<HttpMessageConverter<?>>
- errorHandler: ResponseErrorHandler
下面我们主要针对这些属性做一些分析
requestFactory
指定使用的HTTP请求方式, 设置http请求工厂类,处理超时,线程,异常处理等情况。
| 1 | RestTemplate restTemplate() { | 
defaultUriVariables
当被赋值时就不能使用自定义uriTemplateHandler。这是就使用默认的uriTemplateHandler即DefaultUriBuilderFactory。 假设现在defaultUriVariables包含default=demo。
例如:
| 1 | String url = "http://localhost:8080/{default}/{replace}" | 
在实际请求时: {default}会被替换为demo
{replace}会被替换为someuri
替换后的值中包含/会无法正常解析。
uriTemplateHandler
默认的 uriTemplateHandler 会将 uriVariables 中的 value 进行转译,因此无法'/'会被解析为 ascii 符号。根据需要,生成满足自己需要的 URI。
| 1 | public interface UriTemplateHandler { | 
返回的 URI 经过自定义处理器会将{xxx},替换为uriVariables中对应的值,这个可以正常解析/
| 1 | RestTemplate rest = restTemplate(); | 
interceptors
类似AOP切面,在HTTP请求前后进行拦截,比如统一加`headers
| 1 | public interface ClientHttpRequestInterceptor { | 
messageConverters
与SpringMVC的messageConverters原理是一样的。HTTP交易时数据传递是通过二进制byte传递的。而我们使用RestTemplate时,一般请求返回都使用javaBean,那就需要messageConverters来统一处理。
我们看下RestTemplate的静态方法
| 1 | private static boolean romePresent; | 
再看下RestTemplate构造器,当classpath中有对应的class时,可以看到RestTemplate会自动加载
| 1 | public RestTemplate() { | 
errorHandler
仅在HTTP成功返回后才会被执行,决定当前HTTP请求是否成功。hasError返回true时才会调用handleError方法。
| 1 | public interface ResponseErrorHandler { | 
rootUri
通过RestTemplateBuilder设置rootUri,进行HTTP请求时,若非http开头,则会自动加上rootUri
| 1 | RestTemplate rest = new RestTemplateBuilder().rootUri("http://localhost:8080").build(); | 
POST 请求参数
上传文件的请求模拟
| 1 | RestTemplate restTemplate = new RestTemplate(); | 
上传文件的错误
错误信息
The request was rejected because no multipart boundary was found
通过查找该报错信息打印处可以定位
| 1 | FileItemIteratorImpl(RequestContext ctx) | 
通过查看getBoundary
| 1 | protected byte[] getBoundary(String contentType) { | 
根据上一节的说明,我们知道上送文件是使用MultiValueMap来上送的,那么我们只要知道MultiValueMap请求的Content-Type是什么即可。
根据前面章节messageConverters的加载介绍,我们知道RestTemplate会选择一个合适的处理器来处理, 其中AllEncompassingFormHttpMessageConverter的父类FormHttpMessageConverter
| 1 | public void doWithRequest(ClientHttpRequest httpRequest) throws IOException { | 
查看具体FormHttpMessageConverter的write方法
| 1 | public void write(MultiValueMap<String, ?> map, @Nullable MediaType contentType, HttpOutputMessage outputMessage) | 
| 1 | private void writeMultipart(final MultiValueMap<String, Object> parts, HttpOutputMessage outputMessage) | 
所以我们定位一下具体发生错误的情况下使用的是何种messageConverter即可
messageConverter有关问题
当请求的api返回的content-type不是标准的application/json时,默认的messageConverter不支持处理
| 1 | List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>(); |