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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 08:22:37