![](/img/trans.png)
[英]Spring RestTemplate HTTP Post with parameters cause 400 bad request error
[英]Spring RestTemplate post using parameters in a HashMap throws 400 Bad Request
當我使用 Spring RestTemplate.postForObject
使用HashMap
發布參數時,服務器拋出 400 Bad Request:
Map<String, Object> uriVariables = new HashMap<>();
uriVariables.put("param1", "param1val");
restTemplate.postForObject(url, uriVariables, responseType);
日志:
14:51:20.102 [main] DEBUG org.springframework.web.client.RestTemplate - Created POST request for "http://localhost:8080/demo-1/test"
14:51:20.113 [main] DEBUG org.springframework.web.client.RestTemplate - Setting request Accept header to [text/plain, application/json, application/*+json, */*]
14:51:20.161 [main] DEBUG org.springframework.web.client.RestTemplate - Writing [{param1=1}] using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@8e24743]
14:51:20.225 [main] DEBUG org.springframework.web.client.RestTemplate - POST request for "http://localhost:8080/demo-1/test" resulted in 400 (null); invoking error handler
Exception in thread "main" org.springframework.web.client.HttpClientErrorException: 400 null
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:78)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:653)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:380)
但是如果我使用MultiValueMap
,它就可以工作。
MultiValueMap<String, Object> uriVariables = new LinkedMultiValueMap<>();
uriVariables.add("param1", "param1val");
restTemplate.postForObject(url, uriVariables, responseType);
日志:
14:52:08.493 [main] DEBUG org.springframework.web.client.RestTemplate - Created POST request for "http://localhost:8080/demo-1/test"
14:52:08.501 [main] DEBUG org.springframework.web.client.RestTemplate - Setting request Accept header to [text/plain, application/json, application/*+json, */*]
14:52:08.502 [main] DEBUG org.springframework.web.client.RestTemplate - Writing [{param1=[1]}] using [org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter@4abdb505]
14:52:08.537 [main] DEBUG org.springframework.web.client.RestTemplate - POST request for "http://localhost:8080/demo-1/test" resulted in 200 (null)
14:52:08.539 [main] DEBUG org.springframework.web.client.RestTemplate - Reading [java.lang.String] as "text/plain;charset=UTF-8" using [org.springframework.http.converter.StringHttpMessageConverter@13c27452]
{"name":"1"}
這是控制器方法:
@RequestMapping(name = "/test", method = RequestMethod.POST)
@ResponseBody
public String test(@RequestParam("param1") final String param1) {
// some class Test
final Test test = new Test();
test.setName(param1);
return JsonUtils.toJson(test);
}
有人可以解釋為什么使用HashMap
傳遞請求參數不起作用嗎?
當你說: it throws 400 Bad Request:
你明白它指的是it
嗎? 提示:它不是 Spring REST 客戶端代碼,而是您正在與之交談的服務器,它不接受您的 http 請求為有效。
您可以激活 spring restTemplate 使用的 httpclient 實現的日志記錄,以查看從HashMap
到LinkedMultiValueMap
如何更改生成的 http 請求。
您還可以查看 spring restTemplate 源代碼以了解為什么會生成不同的請求。
編輯:您發布的日志的重要部分:
14:51:20.161 [main] 調試 org.springframework.web.client.RestTemplate - 使用 [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@8e24743] 編寫 [{param1=1}]
這里肯定是在 http 請求正文上寫 json
使用 LinkedMultiValueMap 時:
14:52:08.502 [main] DEBUG org.springframework.web.client.RestTemplate - 使用 [org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter@4abdb505] 編寫 [{param1=[1]}]
在第一種情況下,您的請求不會有參數param1
而是請求正文中的所有數據,而在第二種情況下,您會得到一個param1
參數,使請求對服務器有效
應該可以通過擴展/創建消息轉換器來配置RestTemplate
以使用HashMap
以您想要的方式工作,但我建議您使用LinkedMultiValueMap
有兩個原因:
MultiValueMap 與 HashMap 具有不同的值類型。 在其接口定義中可以看出:
interface MultiValueMap<K, V> extends Map<K, List<V>>
和哈希映射:
class HashMap<K,V> extends AbstractMap<K,V>
你使用put
方法填充HashMap, add
方法填充MultiValueMap,看起來很相似,但實際上MultiValueMap保存的是lists ,而不是單個值。 它可以在您的日志中看到:
哈希映射:
14:51:20.161 [main] 調試 org.springframework.web.client.RestTemplate - 編寫 [{param1=1}]
多值映射:
14:52:08.502 [main] 調試 org.springframework.web.client.RestTemplate - 編寫 [{param1= 1 }]
如您所見, {param1=1}
不起作用,而{param1=[1]}
起作用。
此外,在RestTemplate
的文檔中建議使用 MultiValueMap:
實體的主體或請求本身可以是 MultiValueMap 以創建多部分請求。 MultiValueMap 中的值可以是表示部件主體的任何對象,也可以是表示具有主體和標頭的部件的 HttpEntity。 可以使用 MultipartBodyBuilder 方便地構建 MultiValueMap。
您可以選擇使用HttpHeaders
和HttpEntity
以及MultiValueMap
或hashMap
。 你查找這個關鍵字和鏈接。 可能有用。
這是示例代碼:
HttpHeaders headers = new HttpHeaders();
headers.add("x-sample-session-id", sampleService.getServerSessionId());
MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
map.add("file", new ByteArrayResource(model.getFile().getBytes()));
map.add("apList", model.getApList());
HttpEntity<?> request = new HttpEntity<Object>(map, headers);
String url = sampleService.getContextPath() + "/thirdParty/" + sampleService.getThirdPartyId() + "/child/"
+ childId + "/location?sessionId=" + childSessionId
+ "&op=sendOnDemandLocationResponseWithPhoto&latitude=" + latitude + "&longitude=" + longitude
+ "&datetime=" + datetime + "&provider=" + provider + "&guardianId=" + guardianId + "&cellInfos="
+ cellInfos + "×tamp=" + timestamp + "&battery=" + battery;
RestTemplate rest = new RestTemplate();
try {
// success
return rest.exchange(url, HttpMethod.POST, request, String.class);
} catch (HttpStatusCodeException e) {
// new Error Response
return ResponseEntity.status(e.getStatusCode()).headers(e.getResponseHeaders())
.body(e.getResponseBodyAsString());
}
要使用HashMap
使其工作,請嘗試以下操作:-
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
messageConverters.add(new MappingJackson2HttpMessageConverter());
restTemplate.setMessageConverters(messageConverters);
說明
默認情況下,RestTemplate 在構造函數中設置了許多 MessageConverters,如下所示
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(new StringHttpMessageConverter());
this.messageConverters.add(new ResourceHttpMessageConverter(false));
this.messageConverters.add(new SourceHttpMessageConverter<>());
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
它還自動添加了MappingJackson2HttpMessageConverter
但那是在AllEncompassingFormHttpMessageConverter
之后
這不起作用(非常奇怪),因為AllEncompassingFormHttpMessageConverter
在MappingJackson2HttpMessageConverter
實際工作之前接管並返回
if (jackson2Present) {
this.messageConverters.add(new MappingJackson2HttpMessageConverter());
}
類AllEncompassingFormHttpMessageConverter
擴展了FormHttpMessageConverter
,它實現了HttpMessageConverter<MultiValueMap<String, ?>>
,這里MultiValueMap
是需要注意的。
而在MappingJackson2HttpMessageConverter
的情況下,它擴展了AbstractJackson2HttpMessageConverter
,它進一步擴展了AbstractGenericHttpMessageConverter<Object>
並在此處注意Object
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.