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

使用Spring RestTemplate调用Amazon Cognito获取令牌时出现405 Method Not Allowed错误的求助

问题:Spring RestTemplate调用Amazon Cognito令牌接口返回405 Method Not Allowed

我尝试用Spring RestTemplate从Amazon Cognito获取令牌,但收到了405 Method Not Allowed错误,错误栈如下:

org.springframework.web.client.HttpClientErrorException$MethodNotAllowed: 405 Method Not Allowed: [no body]
	at org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:117)
	at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:186)
	at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:125)
	at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63)
	at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:819)
	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:777)
	at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:711)
	at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:602)

我的Java代码如下(已隐去敏感信息):

Map<String, String> params = new LinkedHashMap<>();
params.put("grant_type", "client_credentials");
// build the url with params
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("https://company.auth.eu-west-1.amazoncognito.com/oauth2/token");
for (Map.Entry<String, String> entry : params.entrySet()) {
    builder.queryParam(entry.getKey(), entry.getValue());
}
Map<String, String> headers = new LinkedHashMap<>();
headers.put(AUTHORIZATION, "Basic aHash==");
headers.put("Content-Type", "application/x-www-form-urlencoded");
log.error("GenerateRemoteTokenURI requesting: {}", builder.toUriString());
HttpEntity<String> tokenResponseEntity = restTemplate.exchange(builder.toUriString(), HttpMethod.POST, new HttpEntity<>(headers), String.class);

但我用curl执行相同逻辑的请求却能正常拿到access_token:

curl --location --request POST 'https://company.eu-west-1.amazoncognito.com/oauth2/token?grant_type=client_credentials' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic aHash=='

为什么RestTemplate会报错?该怎么解决?


原因分析

问题出在请求参数的传递方式和请求体的构造上:

  1. Amazon Cognito的/oauth2/token接口(client_credentials模式)要求POST请求的参数以application/x-www-form-urlencoded格式放在请求体中,而非URL的查询参数里。虽然curl请求中把grant_type放在URL里也能工作,但这不是标准的OAuth2 client_credentials模式的请求方式,Cognito可能做了兼容,但RestTemplate的请求构造不符合接口的核心要求。

  2. 你的RestTemplate代码中,HttpEntity只传入了headers,没有携带任何请求体内容(第三个参数是new HttpEntity<>(headers),请求体为null)。而接口明确要求POST请求必须携带表单格式的请求体,这就导致服务器返回405 Method Not Allowed——本质是请求不符合接口的参数要求,服务器拒绝处理。


解决方案

调整代码,将请求参数放在请求体中,而不是URL的查询参数里,同时正确构造包含表单参数的HttpEntity:

// 1. 构造表单参数,使用MultiValueMap适配x-www-form-urlencoded格式的多值要求
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("grant_type", "client_credentials");

// 2. 构造请求头,用Spring的HttpHeaders类更规范
HttpHeaders headers = new HttpHeaders();
headers.set(AUTHORIZATION, "Basic aHash==");
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

// 3. 构造包含参数和头的HttpEntity
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(params, headers);

// 4. 发送POST请求,直接使用基础URL,无需拼接查询参数
String tokenUrl = "https://company.auth.eu-west-1.amazoncognito.com/oauth2/token";
HttpEntity<String> tokenResponseEntity = restTemplate.exchange(
    tokenUrl, 
    HttpMethod.POST, 
    requestEntity, 
    String.class
);

关键调整点:

  • 使用MultiValueMap而非普通Map存储表单参数,符合application/x-www-form-urlencoded格式的参数规范,Spring对其有原生支持。
  • 将参数移至请求体,不再拼接URL查询参数,完全遵循OAuth2 client_credentials模式的标准请求格式。
  • 用MediaType.APPLICATION_FORM_URLENCODED设置内容类型,避免手动写字符串可能出现的拼写错误。

这样调整后,请求就完全符合Cognito接口的要求,应该能正常获取access_token了。

内容的提问来源于stack exchange,提问作者Adrien Ruffié

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.01 02:32:28