RestTemplate發(fā)送Post請(qǐng)求報(bào)錯(cuò):414 URI Too Long問(wèn)題及解決
一、報(bào)錯(cuò)背景
使用RestTemplate發(fā)送http Post請(qǐng)求時(shí),返回了一個(gè)報(bào)錯(cuò) 414 URI Too Long。
因?yàn)榉?wù)端是Post請(qǐng)求并用@RequestParam進(jìn)行接收,所以我將參數(shù)都拼接在URL后面,如http://localhost:80/add?name=1&age=2 ,導(dǎo)致URL過(guò)長(zhǎng)。
報(bào)錯(cuò)代碼
RestTemplate restTemplate = new RestTemplate();
// 創(chuàng)建請(qǐng)求體
List<NameValuePair> params = new ArraysList<>();
params.add(new BasicNameValuePair("name","張三"));
params.add(new BasicNameValuePair("age","15"));
//....... 設(shè)置大量?jī)?nèi)容
// 設(shè)置請(qǐng)求頭
HttpHeaders headers = new HttpHeaders();
// 創(chuàng)建HttpEntity對(duì)象
HttpEntity<String> httpEntity = new HttpEntity<>(null,headers);
URI uri = URI.create(url);
if(!CollectionUtils.isEmpty(params)){
String param = URLEncodedUtils.format(params, StandardCharsets.UTF_8);
uri = URI.create(url+"?"+param);
}
// 發(fā)送POST請(qǐng)求
String response = restTemplate.exchange(uri, HttpMethod.POST, httpEntity , String.class).getBody();
報(bào)錯(cuò)內(nèi)容
org.springframework.web.client.HttpClientErrorException : 414 URI Too Long:"<h1>Bad Message 414</h1><pre>reason: URI Too Long</pre>"?
二、問(wèn)題分析:414 URI Too Long
HTTP狀態(tài)碼414表示客戶端發(fā)送的請(qǐng)求URI過(guò)長(zhǎng),服務(wù)器拒絕處理。使用RestTemplate發(fā)送POST請(qǐng)求時(shí)出現(xiàn)該錯(cuò)誤,通常是因?yàn)檎?qǐng)求參數(shù)被錯(cuò)誤地附加到URL中而非請(qǐng)求體中,導(dǎo)致URL超過(guò)服務(wù)器限制長(zhǎng)度。
HTTP協(xié)議規(guī)定,請(qǐng)求的URI長(zhǎng)度不能超過(guò)2083個(gè)字符。這是因?yàn)樵贖TTP/1.1協(xié)議中,請(qǐng)求行和請(qǐng)求頭字段的總長(zhǎng)度被限制在8192字節(jié)(不包括CRLF)。
2.1、常見(jiàn)原因
- 參數(shù)誤放在URL中:POST請(qǐng)求本應(yīng)將參數(shù)放在請(qǐng)求體(Body)中,但實(shí)際被拼接到了URL末尾。
- RestTemplate配置問(wèn)題:未正確配置
HttpMessageConverter,導(dǎo)致參數(shù)無(wú)法序列化到請(qǐng)求體。 - URL編碼問(wèn)題:參數(shù)中包含特殊字符未編碼,進(jìn)一步增加URL長(zhǎng)度。
三、解決方法
本文報(bào)錯(cuò)是由于發(fā)送Post請(qǐng)求時(shí),服務(wù)端的接口用的是@RequestParam接收參數(shù),而不是json,所以以下整理幾種方法發(fā)送@RequestParam入?yún)㈩愋偷腜OST請(qǐng)求。
3.1、使用 LinkedMultiValueMap 處理表單數(shù)據(jù)(推薦)
本方法是將請(qǐng)求參數(shù)放到請(qǐng)求體中,不占用URI的長(zhǎng)度,所以就算請(qǐng)求體比較大,也不會(huì)報(bào)414 URI Too Long的錯(cuò)誤。
示例:
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
// 設(shè)置內(nèi)容類型為 application/x-www-form-urlencoded
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
// 使用 MultiValueMap 存放表單數(shù)據(jù)
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("key1", "value1");
formData.add("key2", "value2");
// ... 可以添加很多對(duì),只要不超出服務(wù)器對(duì)Body大小的通常寬松限制
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);
ResponseEntity<String> response = restTemplate.postForEntity(
"http://your-api-endpoint.com/api/resource",
requestEntity,
String.class
);
3.2、將參數(shù)拼接到URI上
如果你只是想在URL中包含查詢參數(shù),可以使用Uri來(lái)構(gòu)建URL。
RestTemplate restTemplate = new RestTemplate();
// 創(chuàng)建請(qǐng)求體
List<NameValuePair> params = new ArraysList<>();
params.add(new BasicNameValuePair("name","張三"));
params.add(new BasicNameValuePair("age","15"));
//....... 設(shè)置大量?jī)?nèi)容
// 設(shè)置請(qǐng)求頭
HttpHeaders headers = new HttpHeaders();
// 創(chuàng)建HttpEntity對(duì)象
HttpEntity<String> httpEntity = new HttpEntity<>(null,headers);
URI uri = URI.create(url);
if(!CollectionUtils.isEmpty(params)){
String param = URLEncodedUtils.format(params, StandardCharsets.UTF_8);
uri = URI.create(url+"?"+param);
}
// 發(fā)送POST請(qǐng)求
String response = restTemplate.exchange(uri, HttpMethod.POST, httpEntity , String.class).getBody();
四、避免誤區(qū)
- 不要使用RestTemplate的getForObject發(fā)送 POST 請(qǐng)求(GET 請(qǐng)求參數(shù)只能在 URL 中,本身就容易觸發(fā) 414)。
- 即使是 POST 請(qǐng)求,若通過(guò)url + “?key=” + value拼接參數(shù),本質(zhì)仍是將參數(shù)放在 URL 中,會(huì)導(dǎo)致同樣的錯(cuò)誤。
- 若接口必須要求參數(shù)在 URL 中(不符合 POST 規(guī)范,但某些舊接口可能如此),則需要縮短參數(shù)長(zhǎng)度,或聯(lián)系服務(wù)器端放寬 URL 長(zhǎng)度限制(不推薦,因?yàn)?URL 長(zhǎng)度本身有協(xié)議限制)。
五、總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Java RestTemplate post請(qǐng)求參數(shù)問(wèn)題及解決
- RestTemplate().postForEntity的參數(shù)使用及說(shuō)明
- 使用restTemplate.postForEntity()的問(wèn)題
- RestTemplate如何使用JSON發(fā)送Post請(qǐng)求
- RestTemplate報(bào)錯(cuò)I/O?error?on?POST?request?for的解決辦法
- restTemplate發(fā)送get與post請(qǐng)求并且?guī)?shù)問(wèn)題
- RestTemplate調(diào)用POST和GET請(qǐng)求示例詳解
- RestTemplate發(fā)送HTTP?POST請(qǐng)求使用方法詳解
相關(guān)文章
SpringBoot整合RocketMq實(shí)現(xiàn)分布式事務(wù)
這篇文章主要為大家詳細(xì)介紹了SpringBoot整合RocketMq實(shí)現(xiàn)分布式事務(wù)的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),有需要的小伙伴可以參考一下2024-11-11
Java解決線程的不安全問(wèn)題之volatile關(guān)鍵字詳解
這篇文章主要介紹了Java解決線程的不安全問(wèn)題之volatile關(guān)鍵字詳解,可見(jiàn)性指一個(gè)線程對(duì)共享變量值的修改,能夠及時(shí)地被其他線程看到,而 volatile 關(guān)鍵字就保證內(nèi)存的可見(jiàn)性,需要的朋友可以參考下2023-08-08
SpringBoot如何優(yōu)雅的整合Swagger Api自動(dòng)生成文檔
在多人協(xié)作的開(kāi)發(fā)過(guò)程中,API文檔不僅可以減少等待,也能保證開(kāi)發(fā)的持續(xù)進(jìn)行,這篇文章主要給大家介紹了關(guān)于SpringBoot如何優(yōu)雅的整合Swagger Api自動(dòng)生成文檔的相關(guān)資料,需要的朋友可以參考下2021-07-07
Java多線程定時(shí)器Timer原理及實(shí)現(xiàn)
這篇文章主要介紹了Java多線程定時(shí)器Timer原理及實(shí)現(xiàn),涉及Timer的schedule的使用,定時(shí)器Timer的schedule等相關(guān)內(nèi)容以及代碼示例,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11
Java String源碼分析并介紹Sting 為什么不可變
這篇文章主要介紹了Java String源碼分析并介紹Sting 為什么不可變的相關(guān)資料,需要的朋友可以參考下2017-02-02
Java中遍歷Map的多種方法示例及優(yōu)缺點(diǎn)總結(jié)
在java中遍歷Map有不少的方法,下面這篇文章主要給大家介紹了關(guān)于Java中遍歷Map的多種方法,以及各種方法的優(yōu)缺點(diǎn)總結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-07-07
SpringBoot多環(huán)境配置與啟動(dòng)banner修改的操作詳解
這篇文章主要介紹了如何自定義SpringBoot的啟動(dòng)banner和設(shè)置多環(huán)境配置,第一部分教如何通過(guò)在線工具生成并配置自定義banner,增強(qiáng)項(xiàng)目辨識(shí)度,第二部分解釋了使用Profile來(lái)管理不同環(huán)境(開(kāi)發(fā)、測(cè)試、生產(chǎn))的配置,需要的朋友可以參考下2025-10-10
Java實(shí)現(xiàn)簡(jiǎn)單密碼加密功能
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)簡(jiǎn)單密碼加密功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-03-03

