使用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会报错?该怎么解决?
问题出在请求参数的传递方式和请求体的构造上:
Amazon Cognito的
/oauth2/token接口(client_credentials模式)要求POST请求的参数以application/x-www-form-urlencoded格式放在请求体中,而非URL的查询参数里。虽然curl请求中把grant_type放在URL里也能工作,但这不是标准的OAuth2 client_credentials模式的请求方式,Cognito可能做了兼容,但RestTemplate的请求构造不符合接口的核心要求。你的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é

