社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
服务端获取不到body的问题:
这个问题坑了我两天了,用RestTemplate、HttpClient、JDK URLConnection写测试类,都试了,一旦设置header的contentType为JSON,服务端拦截器中通过request.getParameterMap()就为{},问题是同样的代码在别人的项目里都能获取到。一开始觉得问题在客户端,试验了十几种设置都还是不能获取,但是仔细看了服务端的代码,发现Conontroller中@RequestBody的地方就能获取。考虑我的项目是Spring3.0.5RELEASE版本且耦合代码不能升级,服务端是4.3.3。
1.网上查了下发现4.3.3的Restemplate的实现类引入了fastJson,可在restemplate.postForObject时自动将JSONString设值到parameterMap中去,3.0.5没这个功能导致。
2.服务端引入的javax.servlet.ServletRequest的jar是javax.servlet-api-3.1.0.jar;getParameterMap的原型为:
public Map<String, String[]> getParameterMap();
所以如果header的contentType不是JSON:requestEntity只能用List类型的MultiValueMap:
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<MultiValueMap<String, Object>>(postParameters, headers);
如果header的contentType为JSON,低版本(3.0.5)的spring-mvc.jar包中的Restemplate将不能设值到ParameterMap中。
解决方案:
服务端拦截器中兼容request.getReader()和request.getParameterMap()获取数据:
ImmutableMap.Builder<String, Object> paramBuilder = ImmutableMap.builder();
if(request.getParameterMap() == null || request.getParameterMap().isEmpty()){
String reqJson = IOUtils.toString(request.getReader());
JSONObject jsonObject = JSON.parseObject(reqJson);
for(String ch:jsonObject.keySet()){
paramBuilder.put(ch,jsonObject.get(ch));
}
}else{
Map<String, String[]> paramMap = request.getParameterMap();
for(String ch:paramMap.keySet()){
paramBuilder.put(ch,paramMap.get(ch));
}
}
客户端以JSON方式调用即可!:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> formEntity = new HttpEntity<String>(jsonStr, headers);
String result = restTemplate.postForObject(interUrl, formEntity, String.class);
所以这个坑了我两天的问题回过来看,有时问题不一定在客户端,服务端的兼容性也很重要!
RestTemplate时去提示信息错误
相同的参数(接口的入参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发送时情况:
使用上面的代码调接口时的http数据情况:
/**
* 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的过滤器:
1 |
|
Tips:
wireshark是非常流行的网络封包分析软件,功能十分强大。可以截取各种网络封包,显示网络封包的详细信息。使用wireshark的人必须了解网络协议,否则就看不懂wireshark了。
为了安全考虑,wireshark只能查看封包,而不能修改封包的内容,或者发送封包。
wireshark能获取HTTP,也能获取HTTPS,但是不能解密HTTPS,所以wireshark看不懂HTTPS中的内容,总结,如果是处理HTTP,HTTPS 还是用Fiddler, 其他协议比如TCP,UDP 就用wireshark.
过滤表达式的规则
表达式规则
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)
封包列表的面板中显示,编号,时间戳,源地址,目标地址,协议,长度,以及封包信息。 你可以看到不同的协议用了不同的颜色显示。
http://blog.csdn.net/holandstone/article/details/47026213
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的操作。
http://blog.csdn.net/u013979547/article/details/52564316
我没有找到任何例子来解决我的问题,所以我想请你帮忙。我不能简单地使用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辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:gxnotes#qq.com(#替换为@)。
本文由《共享笔记》整理, 博文地址: https://gxnotes.com/article/61287.html
https://gxnotes.com/article/61287.html
泛型无法接收:
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);
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!