一、报错背景
使用resttemplate发送http post请求时,返回了一个报错 414 uri too long。
因为服务端是post请求并用@requestparam进行接收,所以我将参数都拼接在url后面,如http://localhost:80/add?name=1&age=2 ,导致url过长。
报错代码
resttemplate resttemplate = new resttemplate();
// 创建请求体
list<namevaluepair> params = new arrayslist<>();
params.add(new basicnamevaluepair("name","张三"));
params.add(new basicnamevaluepair("age","15"));
//....... 设置大量内容
// 设置请求头
httpheaders headers = new httpheaders();
// 创建httpentity对象
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);
}
// 发送post请求
string response = resttemplate.exchange(uri, httpmethod.post, httpentity , string.class).getbody();
报错内容
org.springframework.web.client.httpclienterrorexception : 414 uri too long:"<h1>bad message 414</h1><pre>reason: uri too long</pre>"
二、问题分析:414 uri too long
http状态码414表示客户端发送的请求uri过长,服务器拒绝处理。使用resttemplate发送post请求时出现该错误,通常是因为请求参数被错误地附加到url中而非请求体中,导致url超过服务器限制长度。
http协议规定,请求的uri长度不能超过2083个字符。这是因为在http/1.1协议中,请求行和请求头字段的总长度被限制在8192字节(不包括crlf)。
2.1、常见原因
- 参数误放在url中:post请求本应将参数放在请求体(body)中,但实际被拼接到了url末尾。
- resttemplate配置问题:未正确配置
httpmessageconverter,导致参数无法序列化到请求体。 - url编码问题:参数中包含特殊字符未编码,进一步增加url长度。
三、解决方法
本文报错是由于发送post请求时,服务端的接口用的是@requestparam接收参数,而不是json,所以以下整理几种方法发送@requestparam入参类型的post请求。
3.1、使用 linkedmultivaluemap 处理表单数据(推荐)
本方法是将请求参数放到请求体中,不占用uri的长度,所以就算请求体比较大,也不会报414 uri too long的错误。
示例:
resttemplate resttemplate = new resttemplate();
httpheaders headers = new httpheaders();
// 设置内容类型为 application/x-www-form-urlencoded
headers.setcontenttype(mediatype.application_form_urlencoded);
// 使用 multivaluemap 存放表单数据
multivaluemap<string, string> formdata = new linkedmultivaluemap<>();
formdata.add("key1", "value1");
formdata.add("key2", "value2");
// ... 可以添加很多对,只要不超出服务器对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、将参数拼接到uri上
如果你只是想在url中包含查询参数,可以使用uri来构建url。
resttemplate resttemplate = new resttemplate();
// 创建请求体
list<namevaluepair> params = new arrayslist<>();
params.add(new basicnamevaluepair("name","张三"));
params.add(new basicnamevaluepair("age","15"));
//....... 设置大量内容
// 设置请求头
httpheaders headers = new httpheaders();
// 创建httpentity对象
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);
}
// 发送post请求
string response = resttemplate.exchange(uri, httpmethod.post, httpentity , string.class).getbody();
四、避免误区
- 不要使用resttemplate的getforobject发送 post 请求(get 请求参数只能在 url 中,本身就容易触发 414)。
- 即使是 post 请求,若通过url + “?key=” + value拼接参数,本质仍是将参数放在 url 中,会导致同样的错误。
- 若接口必须要求参数在 url 中(不符合 post 规范,但某些旧接口可能如此),则需要缩短参数长度,或联系服务器端放宽 url 长度限制(不推荐,因为 url 长度本身有协议限制)。
五、总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论