You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring RestTemplate发送x-www-form-urlencoded请求返回400错误求助

问题描述

使用Postman发送POST请求时可正常获得成功响应,但使用Spring RestTemplate发送相同请求时返回如下错误:

"httpCode": "400",
"httpMessage": "Bad Request",
"moreInformation": "One or more required API parameters are missing in the API request."

请求配置要求:Content-Type为application/x-www-form-urlencoded,Accept为application/json。

原有实现代码
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

String clientConf = clientId + ":" +clientSecret;
String base64ClientConf = Base64.getEncoder().encodeToString(clientConf.getBytes());
headers.set("Authorization","Basic "+ base64ClientConf);

MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("grant_type",this.grantType);
map.add("scope",this.scopes);
map.add("username",this.username);
map.add("password",this.password);
map.add("client_id",this.clientId);
map.add("client_secret",this.clientSecret);


URI uri = URI.create("url");
HttpEntity entity = new HttpEntity<>(map,headers);

try {
    ResponseEntity<TokenResponse> queryResponseEntity = restTemplate.exchange(uri.toString(), HttpMethod.POST,entity, TokenResponse.class);
    TokenResponse queryResponses = queryResponseEntity.getBody();
    System.out.println(queryResponses);
} catch (HttpClientErrorException | HttpServerErrorException httpClientOrServerExc) {
    System.out.println("RestTemplate response Code =  " + httpClientOrServerExc.getStatusCode() + " Hata = " + httpClientOrServerExc.getMessage());
    throw new Exception("RestTemplate response Code =  " + httpClientOrServerExc.getStatusCode() + " Hata = " + httpClientOrServerExc.getMessage());
}
Postman参考配置
  • 请求Body配置:Postman请求体截图
  • 请求Header配置:Postman请求头截图
问题根因

代码存在3个会触发服务端返回"缺少必填参数"错误的问题:

  1. 客户端凭证重复传递:已经通过Authorization: Basic头传递了client_id和client_secret,又额外把这两个参数放到了form表单请求体中。绝大多数OAuth2接口不允许同时在请求头和请求体中传递客户端凭证,且参考的Postman配置仅在Basic Auth中传了这两个参数,没有在Body中重复添加,两边请求内容不一致。
  2. Base64编码未指定字符集:clientConf.getBytes()会使用操作系统默认字符集编码字符串,在Windows等默认非UTF-8环境下,生成的Base64认证串会解析失败,服务端会判定未传合法的客户端凭证。
  3. 空参数序列化丢失:如果grantType、scopes等字段存在null值,LinkedMultiValueMap在序列化form参数时会直接跳过null值项,导致必填参数缺失。
修复方案
  1. 移除form表单中冗余的client_id、client_secret参数
  2. Base64编码时强制指定UTF-8字符集
  3. 提前校验所有必填参数非空,避免null值被跳过

修复后的核心代码:

// 按需导入java.nio.charset.StandardCharsets、java.util.Objects
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

// 指定UTF-8编码做Base64转换
String clientConf = clientId + ":" + clientSecret;
String base64ClientConf = Base64.getEncoder().encodeToString(clientConf.getBytes(StandardCharsets.UTF_8));
headers.set("Authorization", "Basic " + base64ClientConf);

MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
// 提前校验参数非空,移除冗余的client_id、client_secret
map.add("grant_type", Objects.requireNonNull(this.grantType, "grantType不能为空"));
map.add("scope", Objects.requireNonNull(this.scopes, "scope不能为空"));
map.add("username", Objects.requireNonNull(this.username, "username不能为空"));
map.add("password", Objects.requireNonNull(this.password, "password不能为空"));

URI uri = URI.create("实际请求地址");
HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(map, headers);

try {
    ResponseEntity<TokenResponse> queryResponseEntity = restTemplate.exchange(uri, HttpMethod.POST, entity, TokenResponse.class);
    TokenResponse queryResponses = queryResponseEntity.getBody();
    System.out.println(queryResponses);
} catch (HttpClientErrorException | HttpServerErrorException httpClientOrServerExc) {
    System.out.println("RestTemplate response Code =  " + httpClientOrServerExc.getStatusCode() + " Hata = " + httpClientOrServerExc.getMessage());
    throw new Exception("RestTemplate response Code =  " + httpClientOrServerExc.getStatusCode() + " Hata = " + httpClientOrServerExc.getMessage());
}

注:如果修复后仍然报错,可以在RestTemplate中开启请求日志,打印实际发出的form参数和头信息,和Postman的请求逐字段对比即可定位差异。

内容的提问来源于stack exchange,提问作者safa aytan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 13:54:24