Spring RestTemplate调用AWS托管API遇InvalidMediaTypeException求助
问题分析
这个异常的核心原因很明确:你调用的AWS托管API返回了一个完全无效的Content-Type响应头值——method.request.header.Content-Type,而Spring的MediaType.parseMediaType方法要求MIME类型必须包含/,所以直接触发了InvalidMediaTypeException。修改请求头或者返回类型的思路之所以没用,是因为问题出在响应头的解析环节,和请求端的设置无关。
解决方案
这里提供两种实用的绕过方案,你可以根据自己的代码风格选择:
方案1:手动处理响应流,跳过Content-Type校验
直接绕开Spring默认的响应头校验逻辑,自己读取响应内容并解析:
public List<AccountLocation> getCircuitViewRooms(String clientApiKey) { String uri = circuitApiUrl + "school/rooms?api_key=" + clientApiKey; RestTemplate restTemplate = new RestTemplate(); // 保留Jackson转换器用于后续手动解析 MappingJackson2HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter(); restTemplate.getMessageConverters().clear(); restTemplate.getMessageConverters().add(jacksonConverter); List<AccountLocation> locations = new ArrayList<>(); HttpEntity<?> entity = getHeaders(); // 使用execute方法直接操作响应流,跳过Content-Type校验 String responseBody = restTemplate.execute(uri, HttpMethod.GET, entity, clientHttpResponse -> { // 直接读取响应体为字符串 return StreamUtils.copyToString(clientHttpResponse.getBody(), StandardCharsets.UTF_8); }); // 手动用Jackson解析JSON if (responseBody != null) { ObjectMapper objectMapper = jacksonConverter.getObjectMapper(); CircuitViewRooms[] rooms = objectMapper.readValue(responseBody, CircuitViewRooms[].class); for (CircuitViewRooms room : rooms) { AccountLocation loc = new AccountLocation(); loc.setLocationName(room.getLaundryRooms().getLaundry_room_name()); loc.setLocationId(room.getLocation()); locations.add(loc); } } return locations; }
方案2:自定义容错HttpMessageConverter
如果想保留RestTemplate的exchange调用风格,可以自定义一个转换器,让它忽略无效的Content-Type:
// 自定义容错JSON转换器 public class TolerantJsonConverter extends MappingJackson2HttpMessageConverter { @Override public boolean canRead(Class<?> clazz, MediaType mediaType) { // 允许读取任何类型的响应,不管Content-Type是否有效 return true; } }
然后在你的业务代码中替换默认转换器:
public List<AccountLocation> getCircuitViewRooms(String clientApiKey) { String uri = circuitApiUrl + "school/rooms?api_key=" + clientApiKey; RestTemplate restTemplate = new RestTemplate(); restTemplate.getMessageConverters().clear(); // 使用自定义的容错转换器 restTemplate.getMessageConverters().add(new TolerantJsonConverter()); List<AccountLocation> locations = new ArrayList<>(); HttpEntity<?> entity = getHeaders(); // 现在可以正常用exchange方法直接接收实体类数组了 ResponseEntity<CircuitViewRooms[]> resp = restTemplate.exchange(uri, HttpMethod.GET, entity, CircuitViewRooms[].class); if (resp.getStatusCode() == HttpStatus.OK) { for (CircuitViewRooms room : resp.getBody()) { AccountLocation loc = new AccountLocation(); loc.setLocationName(room.getLaundryRooms().getLaundry_room_name()); loc.setLocationId(room.getLocation()); locations.add(loc); } } return locations; }
额外提醒
你已经在请求头的Accept里指定了application/json,这部分是正确的,可以确保API返回JSON格式内容,不用再调整。问题的本质就是API返回的响应头不规范,我们的解决方案都是绕过Spring对这个无效响应头的校验逻辑而已。
内容的提问来源于stack exchange,提问作者Dashwall
相关产品推荐
相关产品推荐

