首页 > 其他分享 >Spring RestTemplate 专题

Spring RestTemplate 专题

时间:2023-01-03 22:32:29浏览次数:75  
标签:专题 restTemplate Spring request headers RestTemplate new String


相同的参数(接口的入参json打印在日志了)在PostMan中返回预期的数据,但使用RestTemplate时去提示信息错误(参数中汉字)。
这种情况,搞得怀疑对RestTemplate的理解了
使用RestTemplate的代码如下:

JSONObject reqVO = new JSONObject(12);
reqVO.put("token", smsConfig.getToken());
reqVO.put("phones", new String[]{mobile.toString()});//一个或多个号码数组,一次不能超过10
reqVO.put("content", "content,包含汉字");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
String jsonPost = reqVO.toString();
HttpEntity<String> entity = new HttpEntity<>(jsonPost, headers);

ResponseEntity<String> responseEntity = restTemplate.postForEntity(smsConfig.getUrl(), entity, String.class);
String body = responseEntity.getBody();

 

解决办法,通过wireshark抓包:
使用Postman发送时情况:

Spring RestTemplate 专题_RestTemplate

使用上面的代码调接口时的http数据情况:

Spring RestTemplate 专题_RestTemplate_02

 

/**
* A String equivalent of {@link MediaType#APPLICATION_JSON}.
* @see #APPLICATION_JSON_UTF8_VALUE
*/
public final static String APPLICATION_JSON_VALUE = "application/json";

/**
* Public constant media type for {@code application/json;charset=UTF-8}.
*/
public final static MediaType APPLICATION_JSON_UTF8;

只更改上面中设置Content-type的这行代码,更改后的:

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);

 

上面 wireshark的过滤器:

ip.dst==目标接口的ip地址 and tcp.port==80 and http.request.method="POST"

 Tips:

wireshark是非常流行的网络封包分析软件,功能十分强大。可以截取各种网络封包,显示网络封包的详细信息。使用wireshark的人必须了解网络协议,否则就看不懂wireshark了。

为了安全考虑,wireshark只能查看封包,而不能修改封包的内容,或者发送封包。

wireshark能获取HTTP,也能获取HTTPS,但是不能解密HTTPS,所以wireshark看不懂HTTPS中的内容,总结,如果是处理HTTP,HTTPS 还是用Fiddler, 其他协议比如TCP,UDP 就用wireshark.

Spring RestTemplate 专题_RestTemplate_03

过滤表达式的规则

表达式规则

 1. 协议过滤

比如TCP,只显示TCP协议。

2. IP 过滤

比如 ip.src ==192.168.1.102 显示源地址为192.168.1.102,

ip.dst==192.168.1.102, 目标地址为192.168.1.102

3. 端口过滤

tcp.port ==80,  端口为80的

tcp.srcport == 80,  只显示TCP协议的愿端口为80的。

4. Http模式过滤

http.request.method=="GET",   只显示HTTP GET方法的。

5. 逻辑运算符为 AND/ OR

常用的过滤表达式

过滤表达式

用途

http

只查看HTTP协议的记录

ip.src ==192.168.1.102 or ip.dst==192.168.1.102

 源地址或者目标地址是192.168.1.102

 

 

 

 

 

 

 

 

封包列表(Packet List Pane)

封包列表的面板中显示,编号,时间戳,源地址,目标地址,协议,长度,以及封包信息。 你可以看到不同的协议用了不同的颜色显示。


 

restTemplate使用及中文乱码问题

 

public <T> T restTemplate(String url, Map<String,T> params, Class<T> var, HttpMethod method) {
RestTemplate restTemplate = new RestTemplate();
FormHttpMessageConverter fc = new FormHttpMessageConverter();
StringHttpMessageConverter s = new StringHttpMessageConverter(StandardCharsets.UTF_8);
List<HttpMessageConverter<?>> partConverters = new ArrayList<HttpMessageConverter<?>>();
partConverters.add(s);
partConverters.add(new ResourceHttpMessageConverter());
fc.setPartConverters(partConverters);
restTemplate.getMessageConverters().addAll(Arrays.asList(fc, new MappingJackson2HttpMessageConverter()));
MultiValueMap<String, T> map = new LinkedMultiValueMap<>();
map.setAll(params);
switch (method) {
case POST:
return restTemplate.postForObject(url, map, var);
case GET:
String getParams = "?" + map.keySet().stream().map(k -> String.format("%s={%s}", k, k)).collect(Collectors.joining("&"));
return restTemplate.getForObject(url + getParams, var, params);
default:
return restTemplate.postForObject(url, map, var);
}
}

所要注意的是get请求要求我们对URL中参数用占位符封装,user/getUser?userId={userId}&fe=
{fe},就像这样,所以我在封装get请求时有一个拼接URL的操作。


问题描述

我没有找到任何例子来解决我的问题,所以我想请你帮忙。我不能简单地使用JSON中的RestTemplate对象发送POST请求

每次我得到org.springframework.web.client.HttpClientErrorException:415不支持的媒体类型

我以这种方式使用RestTemplate:

...
restTemplate = new RestTemplate();
List<HttpMessageConverter<?>> list = new ArrayList<HttpMessageConverter<?>>();
list.add(new MappingJacksonHttpMessageConverter());
restTemplate.setMessageConverters(list);
...
Payment payment= new Payment("Aa4bhs");
Payment res = restTemplate.postForObject("http://localhost:8080/aurest/rest/payment", payment, Payment.class);

我的错是什么

 

最佳解决方案

这种技术对我有用:

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

HttpEntity<String> entity = new HttpEntity<String>(requestJson,headers);
restTemplate.put(uRL, entity);

我希望这有帮助

KD

 

次佳解决方案

我一直在使用具有JSONObjects的rest模板,如下所示:

// create request body
JSONObject request = new JSONObject();
request.put("username", name);
request.put("password", password);

// set headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(request.toString(), headers);

// send request and parse result
ResponseEntity<String> loginResponse = restTemplate
.exchange(urlString, HttpMethod.POST, entity, String.class);
if (loginResponse.getStatusCode() == HttpStatus.OK) {
JSONObject userJson = new JSONObject(loginResponse.getBody());
} else if (loginResponse.getStatusCode() == HttpStatus.UNAUTHORIZED) {
// nono... bad credentials
}

 

第三种解决方案

尝试调试REST端点时,我遇到这个问题。这是使用Spring的RestTemplate类来创建我使用的POST请求的一个基本示例。我花了很长时间把不同地方的代码整理成一个工作版本。

RestTemplate restTemplate = new RestTemplate();

String url = "endpoint url";
String requestJson = "{\"queriedQuestion\":\"Is there pain in your hand?\"}";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

HttpEntity<String> entity = new HttpEntity<String>(requestJson,headers);
String answer = restTemplate.postForObject(url, entity, String.class);
System.out.println(answer);

特定的JSON解析器我的休息终点是使用围绕字段名称的双引号,这就是为什么我在我的requestJson String中转义了双引号。

 

第四种方案

根据指定的​​here​​​我想你需要添加一个​​messageConverter​​​为​​MappingJacksonHttpMessageConverter​

 

第五种方案

“415不支持的媒体类型”错误告诉您服务器将不接受您的POST请求。您的请求绝对不错,这是mis-configured的服务器。

​MappingJacksonHttpMessageConverter​​​会自动将请求content-type标头设置为​​application/json​​,我的猜测是您的服务器拒绝了。你没有告诉我们任何关于你的服务器设置,所以我不能真的建议你。

 

第六种方案

如果您使用的是Spring 3.0,则可以避免使用org.springframework.web.client.HttpClientErrorException:415不支持的介质类型异常的简单方法是将jackson jar文件包含在类路径中,并使用​​mvc:annotation-driven​​​ config元素。 ​​As specified here​​。

我正在拉我的头发,试图找出为什么​​mvc-ajax​​​应用程序工作没有任何特殊的配置为​​MappingJacksonHttpMessageConverter​​。如果你仔细阅读我所链接的文章:

Underneath the covers, Spring MVC delegates to a HttpMessageConverter to perform the serialization. In this case, Spring MVC invokes a MappingJacksonHttpMessageConverter built on the Jackson JSON processor. This implementation is enabled automatically when you use the mvc:annotation-driven configuration element with Jackson present in your classpath.

参考文献

 

注:本文内容整合自google/baidu/bing辅助翻译的英文资料结果。如果您对结果不满意


RestTemplate

这篇文章打算介绍一下Spring的​​RestTemplate​​​。我这边以前设计到http交互的,之前一直采用的是​​Apache HttpComponents​​ 。后来发现Spring框架中已经为我们封装好了这个框架。因此我们就不需要直接使用下面这种稍微底层一点的方式来实现我们的功能:

String uri = "http://example.com/hotels/1/bookings";

PostMethod post = new PostMethod(uri);
String request = // create booking request content
post.setRequestEntity(new StringRequestEntity(request));

httpClient.executeMethod(post);

if (HttpStatus.SC_CREATED == post.getStatusCode()) {
Header location = post.getRequestHeader("Location");
if (location != null) {
System.out.println("Created new booking at :" + location.getValue());
}
}

Spring的RestTemplate提供了一些更高级别的方法来满足我们的功能,比如对HTTP Method的支持:

Spring RestTemplate 专题_封包_04

虽然Spring的RestTemplate提供了对这么多HTTP method的支持,但是从个人工作角度来说,常用的也就get和post这两种方式,有兴趣的朋友可以自己翻看一下源码。

RestTemplate的使用

RestTemplate有两个构造方法,分别是:

public RestTemplate() {
/**
...初始化过程
*/
}

public RestTemplate(ClientHttpRequestFactory requestFactory) {
this();
setRequestFactory(requestFactory);
}

其中,第二个构造方法中可以传入ClientHttpRequestFactory参数,第一个进行默认初始化,因为我们经常需要对请求超时进行设置并能够对超时进行后续处理,而第一个构造方法,我们无法控制超时时间,第二个构造中的ClientHttpRequestFactory接口的实现类中存在timeout属性,因此选用第二个构造方法。
在spring配置文件中进行如下配置:

<!-- 配置RestTemplate -->
<!--Http client Factory-->
<bean id="httpClientFactory" class="org.springframework.http.client.SimpleClientHttpRequestFactory">
<property name="connectTimeout" value="${connectTimeout}"/>
<property name="readTimeout" value="${readTimeout}"/>
</bean>

<!--RestTemplate-->
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<constructor-arg ref="httpClientFactory"/>
</bean>

当然也可以直接使用:

SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setConnectTimeout(1000);
requestFactory.setReadTimeout(1000);

RestTemplate restTemplate = new RestTemplate(requestFactory);

注意:ClientHttpRequestFactory 接口有4个实现类,分别是:

  • AbstractClientHttpRequestFactoryWrapper 用来装配其他request factory的抽象类。
  • CommonsClientHttpRequestFactory 允许用户配置带有认证和http连接池的httpclient,已废弃,推荐用HttpComponentsClientHttpRequestFactory。
  • HttpComponentsClientHttpRequestFactory 同2.
  • SimpleClientHttpRequestFactory 接口的一个简单实现,可配置proxy,connectTimeout,readTimeout等参数。

GET

Spring的RestTemplate提供了许多的支持,这里仅仅列出常用的接口:

public <T> T getForObject(String url, Class<T> responseType, Object... urlVariables) throws RestClientException 
public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> urlVariables) throws RestClientException
public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException

对于GET请求来说,我一般常用的几种形式如下:

String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/bookings/{booking}", String.class,"42", "21");

或者下面这张形式:

Map<String, String> vars = Collections.singletonMap("hotel", "42");
String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars);

以及:
​​​java String message = restTemplate.getForObject("http://localhost:8080/yongbarservice/appstore/appgoods/restTemplate?name=zhaoshijie&id=80", String.class );​

他这种做法参考了​​uri-templates​​​(​​https://code.google.com/p/uri-templates/)这个项目。​

POST

Spring的RestTemplate对post的常用接口:

public <T> T postForObject(String url, Object request, Class<T> responseType, Object... uriVariables)
throws RestClientException
public <T> T postForObject(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables)
throws RestClientException
public <T> T postForObject(URI url, Object request, Class<T> responseType) throws RestClientException

我一般常用的方法为:

MultiValueMap<String, String> bodyMap = new LinkedMultiValueMap<String, String>();
bodyMap.setAll(urlVariables);
ResponseClass responseClass = restTemplate.postForObject(CAR_CES_URL, bodyMap, ResponseClass.class);

以及:

HttpHeaders headers = new HttpHeaders();
headers.add("X-Auth-Token", "e348bc22-5efa-4299-9142-529f07a18ac9");

MultiValueMap<String, String> postParameters = new LinkedMultiValueMap<String, String>();
postParameters.add("owner", "11");
postParameters.add("subdomain", "aoa");
postParameters.add("comment", "");

HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<MultiValueMap<String, String>>(postParameters, headers);

ParseResultVo exchange = null;
try {
exchange = restTemplate.postForObject("http://l-dnsutil1.ops.beta.cn6.qunar.com:10085/v1/cnames/tts.piao", requestEntity, ParseResultVo.class);
logger.info(exchange.toString());
} catch (RestClientException e) {
logger.info("。。。。");
}

以及:

DomainParam domainParam = new DomainParam();
domainParam.setCustomerId(1);
//...

logger.info("....");
restTemplate.getMessageConverters().add(new MappingJacksonHttpMessageConverter());
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
String responseResult = restTemplate.postForObject(url, domainParam, String.class);

其他

​PUT​​方式:

restTemplate.put("http://localhost:8080/yongbarservice/appstore/appgoods/restTemplate?name=zhaoshijie&id=80" ,null);

​DELETE​​方式

//delete方法(注意:delete方法没有返回值,说明,id=0这个参数在服务器端可以不定义该参数,直接使用request获取) 
// restTemplate.delete("http://localhost:8080/yongbarservice/appstore/appgoods/deleteranking?id=0");

参考资料:


1. Overview

In this tutorial, we’re going to illustrate the broad range of operations where the Spring REST Client – RestTemplate – can be used, and used well.

For the API side of all examples, we’ll be running the RESTful service from ​​here​​.

Further reading:

Basic Authentication with the RestTemplate

How to do Basic Authentication with the Spring RestTemplate.

​Read more​​ →

RestTemplate with Digest Authentication

How to set up Digest Authentication for the Spring RestTemplate using HttpClient 4.

​Read more​​ →

HttpClient 4 Tutorial

Comprehensive Guide to the Apache HttpClient - start with basic usage and make your way though the advanced scenarios.

​Read more​​ →

2. Use GET to Retrieve Resources

2.1. Get Plain JSON

Let’s start simple and talk about GET requests – with a quick example using the getForEntity() API:

​​RestTemplate restTemplate = ​​​​new​​​ ​​RestTemplate();​​
​​String fooResourceUrl​​
​​= ​​​​"http://localhost:8080/spring-rest/foos"​​​​;​​
​​ResponseEntity<String> response​​
​​= restTemplate.getForEntity(fooResourceUrl + ​​​​"/1"​​​​, String.​​​​class​​​​);​​
​​assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));​​

Notice that we have full access to the HTTP response – so we can do things like checking the status code to make sure the operation was actually successful, or work with the actual body of the response:

​​ObjectMapper mapper = ​​​​new​​​ ​​ObjectMapper();​​
​​JsonNode root = mapper.readTree(response.getBody());​​
​​JsonNode name = root.path(​​​​"name"​​​​);​​
​​assertThat(name.asText(), notNullValue());​​

We’re working with the response body as a standard String here – and using Jackson (and the JSON node structure that Jackson provides) to verify some details.

2.1. Retrieving POJO Instead of JSON

We can also map the response directly to a Resource DTO – for example:

​​public​​​ ​​class​​​ ​​Foo ​​​​implements​​​ ​​Serializable {​​
​​private​​​ ​​long​​​ ​​id;​​

​​private​​​ ​​String name;​​
​​// standard getters and setters​​
​​}​​

Now – we can simply use the getForObject API in the template:

​​Foo foo = restTemplate​​
​​.getForObject(fooResourceUrl + ​​​​"/1"​​​​, Foo.​​​​class​​​​);​​
​​assertThat(foo.getName(), notNullValue());​​
​​assertThat(foo.getId(), is(1L));​​

3. Use HEAD to Retrieve Headers

Let’s now have a quick look at using HEAD before moving on to the more common methods – we’re going to be using the headForHeaders() API here:

​​HttpHeaders httpHeaders = restTemplate​​
​​.headForHeaders(fooResourceUrl);​​
​​assertTrue(httpHeaders.getContentType()​​
​​.includes(MediaType.APPLICATION_JSON));​​

4. Use POST to Create a Resource

In order to create a new Resource in the API – we can make good use of the postForLocation()postForObject() or postForEntity() APIs.

The first returns the URI of the newly created Resource while the second returns the Resource itself.

4.1. The postForObject API

​​ClientHttpRequestFactory requestFactory = getClientHttpRequestFactory();​​
​​RestTemplate restTemplate = ​​​​new​​​ ​​RestTemplate(requestFactory);​​

​​HttpEntity<Foo> request = ​​​​new​​​ ​​HttpEntity<>(​​​​new​​​ ​​Foo(​​​​"bar"​​​​));​​
​​Foo foo = restTemplate.postForObject(fooResourceUrl, request, Foo.​​​​class​​​​);​​
​​assertThat(foo, notNullValue());​​
​​assertThat(foo.getName(), is(​​​​"bar"​​​​));​​




4.2. The postForLocation API

Similarly, let’s have a look at the operation that – instead of returning the full Resource, just returns the Location of that newly created Resource:

​​HttpEntity<Foo> request = ​​​​new​​​ ​​HttpEntity<>(​​​​new​​​ ​​Foo(​​​​"bar"​​​​));​​
​​URI location = restTemplate​​
​​.postForLocation(fooResourceUrl, request);​​
​​assertThat(location, notNullValue());​​

4.3. The exchange API

Finally, let’s have a look at how to do a POST with the more generic exchange API:

​​RestTemplate restTemplate = ​​​​new​​​ ​​RestTemplate();​​
​​HttpEntity<Foo> request = ​​​​new​​​ ​​HttpEntity<>(​​​​new​​​ ​​Foo(​​​​"bar"​​​​));​​
​​ResponseEntity<Foo> response = restTemplate​​
​​.exchange(fooResourceUrl, HttpMethod.POST, request, Foo.​​​​class​​​​);​​

​​assertThat(response.getStatusCode(), is(HttpStatus.CREATED));​​

​​Foo foo = response.getBody();​​

​​assertThat(foo, notNullValue());​​
​​assertThat(foo.getName(), is(​​​​"bar"​​​​));​​

5. Use OPTIONS to get Allowed Operations

Next, we’re going to have a quick look at using an OPTIONS request and exploring the allowed operations on a specific URI using this kind of request; the API is optionsForAllow:

​​Set<HttpMethod> optionsForAllow = restTemplate.optionsForAllow(fooResourceUrl);​​
​​HttpMethod[] supportedMethods​​
​​= {HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, HttpMethod.DELETE};​​
​​assertTrue(optionsForAllow.containsAll(Arrays.asList(supportedMethods)));​​

6. Use PUT to Update a Resource

Next, we’ll start looking at PUT – and more specifically the exchange API for this operation, because of the template.put API is pretty straightforward.

6.1. Simple PUT with .exchange

We’ll start with a simple PUT operation against the API – and keep in mind that the operation isn’t returning anybody back to the client:

​​Foo updatedInstance = ​​​​new​​​ ​​Foo(​​​​"newName"​​​​);​​
​​updatedInstance.setId(createResponse.getBody().getId());​​
​​String resourceUrl = ​​
​​fooResourceUrl + ​​​​'/'​​​ ​​+ createResponse.getBody().getId();​​
​​HttpEntity<Foo> requestUpdate = ​​​​new​​​ ​​HttpEntity<>(updatedInstance, headers);​​
​​template.exchange(resourceUrl, HttpMethod.PUT, requestUpdate, Void.​​​​class​​​​);​​

6.2. PUT with .exchange and a Request Callback

Next, we’re going to be using a request callback to issue a PUT.

Let’s make sure we prepare the callback – where we can set all the headers we need as well as a request body:

​​RequestCallback requestCallback(​​​​final​​​ ​​Foo updatedInstance) {​​
​​return​​​ ​​clientHttpRequest -> {​​
​​ObjectMapper mapper = ​​​​new​​​ ​​ObjectMapper();​​
​​mapper.writeValue(clientHttpRequest.getBody(), updatedInstance);​​
​​clientHttpRequest.getHeaders().add(​​
​​HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);​​
​​clientHttpRequest.getHeaders().add(​​
​​HttpHeaders.AUTHORIZATION, ​​​​"Basic "​​​ ​​+ getBase64EncodedLogPass());​​
​​};​​
​​}​​

Next, we create the Resource with POST request:

​​ResponseEntity<Foo> response = restTemplate​​
​​.exchange(fooResourceUrl, HttpMethod.POST, request, Foo.​​​​class​​​​);​​
​​assertThat(response.getStatusCode(), is(HttpStatus.CREATED));​​

And then we update the Resource:

​​Foo updatedInstance = ​​​​new​​​ ​​Foo(​​​​"newName"​​​​);​​
​​updatedInstance.setId(response.getBody().getId());​​
​​String resourceUrl =fooResourceUrl + ​​​​'/'​​​ ​​+ response.getBody().getId();​​
​​restTemplate.execute(​​
​​resourceUrl, ​​
​​HttpMethod.PUT, ​​
​​requestCallback(updatedInstance), ​​
​​clientHttpResponse -> ​​​​null​​​​);​​

7. Use DELETE to Remove a Resource

To remove an existing Resource we’ll make short work of the delete() API:

​​String entityUrl = fooResourceUrl + ​​​​"/"​​​ ​​+ existingResource.getId();​​
​​restTemplate.delete(entityUrl);​​

8. Configure Timeout

We can configure RestTemplate to time out by simply using ClientHttpRequestFactory – as follows:

​​RestTemplate restTemplate = ​​​​new​​​ ​​RestTemplate(getClientHttpRequestFactory());​​

​​private​​​ ​​ClientHttpRequestFactory getClientHttpRequestFactory() {​​
​​int​​​ ​​timeout = ​​​​5000​​​​;​​
​​HttpComponentsClientHttpRequestFactory clientHttpRequestFactory​​
​​= ​​​​new​​​ ​​HttpComponentsClientHttpRequestFactory();​​
​​clientHttpRequestFactory.setConnectTimeout(timeout);​​
​​return​​​ ​​clientHttpRequestFactory;​​
​​}​​

And we can use HttpClient for further configuration options – as follows:

​​private​​​ ​​ClientHttpRequestFactory getClientHttpRequestFactory() {​​
​​int​​​ ​​timeout = ​​​​5000​​​​;​​
​​RequestConfig config = RequestConfig.custom()​​
​​.setConnectTimeout(timeout)​​
​​.setConnectionRequestTimeout(timeout)​​
​​.setSocketTimeout(timeout)​​
​​.build();​​
​​CloseableHttpClient client = HttpClientBuilder​​
​​.create()​​
​​.setDefaultRequestConfig(config)​​
​​.build();​​
​​return​​​ ​​new​​​ ​​HttpComponentsClientHttpRequestFactory(client);​​
​​}​​

9. Conclusion

We went over the main HTTP Verbs, using RestTemplate to orchestrate requests using all of these.

If you want to dig into how to do authentication with the template – check out my write-up ​​on Basic Auth with RestTemplate​​.

The implementation of all these examples and code snippets can be found in my GitHub project

​http://www.baeldung.com/rest-template​

RestTemplate:
设置代理

Configure RestTemplate to Use a Proxy
As described in Section 33.1, “RestTemplate Customization”, you can use a RestTemplateCustomizer with RestTemplateBuilder to build a customized RestTemplate.
This is the recommended approach for creating a RestTemplate configured to use a proxy.

The exact details of the proxy configuration depend on the underlying client request factory that is being used.
The following example configures HttpComponentsClientRequestFactory with an HttpClient that uses a proxy for all hosts except 192.168.0.5:

static class ProxyCustomizer implements RestTemplateCustomizer {

@Override
public void customize(RestTemplate restTemplate) {
HttpHost proxy = new HttpHost("proxy.example.com");
HttpClient httpClient = HttpClientBuilder.create()
.setRoutePlanner(new DefaultProxyRoutePlanner(proxy) {

@Override
public HttpHost determineProxy(HttpHost target,
HttpRequest request, HttpContext context)
throws HttpException {
if (target.getHostName().equals("192.168.0.5")) {
return null;
}
return super.determineProxy(target, request, context);
}

}).build();
restTemplate.setRequestFactory(
new HttpComponentsClientHttpRequestFactory(httpClient));
}

}

​https://docs.spring.io/spring-boot/docs/2.0.0.RELEASE/reference/htmlsingle/#howto-reload-thymeleaf-content​

RestTempate中处理返回值中带有泛型的API:
resttemplate是一个很方便的HTTP客户端,但是当返回的数据类型是泛型时会报错

//一般用法,通过postForObject获取结果
REST_TEMPLATE.postForObject(supplier.getApi(),param,Result.class)
//Result.java
public class Result<T> {
private int code;
private List<T> data;
...
}
//报错
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to xxx

原因:
postForObject无法知道具体的实例化类型,解析为了LinkedHashMap
解决方法,使用exchange方法替代:

Map<String,Object> param = new HashedMap();
param.put("key","value");//传入参数
parameterizedTypeReference =
new ParameterizedTypeReference<Result<XXX>>(){};
//XXX为实例化的类型
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(new Gson().toJson(param),headers);
ResponseEntity<YunResult<Instance>> result =
REST_TEMPLATE.exchange(url, HttpMethod.POST, entity,
parameterizedTypeReference);

链接:https://www.jianshu.com/p/597066dec24d

 

上传文件:
使用RestTemplate调用文件上传接口时有什么特别的地方呢?实际上只需要注意一点就行了,就是创建文件资源时需要使用org.springframework.core.io.FileSystemResource类,而不能直接使用java.io.File对象。

URI uri = UriComponentsBuilder.fromHttpUrl("https://qyapi.weixin.qq.com/cgi-bin/media/upload")
.queryParam("access_token", cpToken)
.queryParam("type", file.getParaName())
.build().toUri();
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
FileSystemResource resource = new FileSystemResource(targetFile);//文件,使用FileSystemResource才能判断出类型
body.add("media", resource);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
httpHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(body, httpHeaders);
ResponseEntity<String> mediaDTOResponseEntity = restTemplate.postForEntity(uri, request, String.class);

​https://work.weixin.qq.com/api/doc/90000/90135/90253​

我有一个servlet,它能够接收二进制数据[文件].
我想使用Spring的RestTemplate()将大型二进制文件上传到servlet.但是,无法将二进制文件完全加载到内存中.
到目前为止,我的尝试导致OutOfMemory错误,表明方法一直在尝试将整个文件加载到内存中.
如何将此二进制数据流式传输到servlet?优选在Spring或Java中.
找到答案:
https://jira.springsource.org/browse/SPR-7909

SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setBufferRequestBody(false);
RestTemplate rest = new RestTemplate(requestFactory);
这可以防止将整个请求加载到内存中.

微信企业号开发:上传文件错误44001,"errmsg":"empty media data

上传文件是经常出现错误"errcode":44001,"errmsg":"empty media data

对照文档一直很难发发小错误,最后才发现是因为缺少了回车换行符

1开始boundary之后需要一个回车换行

2Content-Type之后需要两个回车换行

3文件内容结束后需要一个回车换行

4结束boundary之后需要一个回车换行

/// <summary>
/// 执行带文件上传的HTTP POST请求。
/// </summary>
/// <param name="url">请求地址</param>
/// <param name="fileParams">请求文件参数</param>
/// <returns>HTTP响应</returns>
public string DoPostFile(string url, FileItem fileParams)
{
try
{
string boundary = DateTime.Now.Ticks.ToString("X"); // 随机分隔线
string startboundary = "--" + boundary;
string endboundary = "--" + boundary + "--";
HttpWebRequest req = GetWebRequest(url, "POST");
req.ContentType = "multipart/form-data;boundary=" + boundary;
System.IO.Stream reqStream = req.GetRequestStream();
//开始结束的换行符不能少,否则是44001,"errmsg":"empty media data,
byte[] endBoundaryBytes = Encoding.UTF8.GetBytes("\r\n" + endboundary + "\r\n");
string name = fileParams.GetFileName();
string filename = fileParams.GetFileName();
//结束的两个换行符不能少,否则是44001,"errmsg":"empty media data,
string fileTemplate = "Content-Disposition: form-data; name=\"{0}\";filename=\"{1}\"; filelength={2}\r\nContent-Type: {3}\r\n\r\n";
FileItem fileItem = fileParams;
byte[] fileBytes = fileItem.GetContent();
StringBuilder sb = new StringBuilder();
sb.Append(startboundary);
sb.Append("\r\n");
sb.Append(string.Format(fileTemplate, name, filename, fileBytes.Length, fileItem.GetMimeType()));
// LogInfo.Error("sb.ToString()=" + sb.ToString());
byte[] Content = Encoding.UTF8.GetBytes(sb.ToString());
//开始标志
reqStream.Write(Content, 0, Content.Length);
//文件内容
reqStream.Write(fileBytes, 0, fileBytes.Length);
//结束标志
reqStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
// LogInfo.Error("endBoundaryBytes=" + endboundary);
reqStream.Close();
HttpWebResponse rsp = (HttpWebResponse)req.GetResponse();
Encoding encoding = Encoding.GetEncoding(rsp.CharacterSet);
return GetResponseAsString(rsp, encoding);
}
catch (WebException ex)
{
LogInfo.Error("调用微信接口异常WebException,this._timeout" + this._timeout + ",url=" + url, ex);
ReturnResult rt = new ReturnResult();
rt.errcode = 41001;
rt.errmsg = "调用微信接口异常WebException;" + ex.Message;
return Tools.ToJsonString(rt);
}
}


restTemplate转发接收的文件,直接上传图片。
用multipart形式上传文件时,需要用到MultiValueMap<String, Object>类,用它装载文件对象以及multipart的表单数据。
这里涉及到一个文件,从request中拿文件往MultiValueMap放时,不能直接request.getFile()给multiValueMap,这样在restTemplate上传文件时,messageConverter转化时会报错,需要把request.getFile("file").getResource()的数据给multiValueMap。代码如下:

public UploadResponseVO resendUpload(String url,StandardMultipartHttpServletRequest request) throws IOException {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
parts.add("file",request.getFile("file").getResource());
Enumeration<String> enumeration= request.getParameterNames();
while(enumeration.hasMoreElements()){
String key = enumeration.nextElement();
parts.add(key,request.getParameter(key));
}
HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(parts, headers);
ResponseEntity<UploadResponseVO> responseEntity = restTemplate.postForEntity(url,httpEntity,UploadResponseVO.class);
return responseEntity.getBody();
}

 









标签:专题,restTemplate,Spring,request,headers,RestTemplate,new,String
From: https://blog.51cto.com/u_15147537/5986868

相关文章