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

使用Spring WebClient读取OGC WFS的GML数据时遭遇InvalidMediaTypeException异常

使用Spring WebClient读取OGC WFS的GML数据时遭遇InvalidMediaTypeException异常

我在尝试用Spring WebClient从OGC WFS源读取GML数据时碰到了一个头疼的问题——服务要求的输出格式参数是OUTPUTFORMAT=text/xml;%20subtype=gml/3.1.1,但这会触发Spring抛出以下异常:

org.springframework.http.InvalidMediaTypeException: Invalid mime type "text/xml; subtype=gml/3.1.1;charset=UTF-8": Invalid token character '/' in token "gml/3.1.1"

我的调用代码是这样的:

private static final WebClient webClient = WebClient.create();

public static String fetchRemoteText(String url) {
    try {
        return webClient.get().uri(url).retrieve().bodyToMono(String.class).doOnSuccess(body -> {
            if (body == null || body.isBlank()) {
                log.info("Empty result returned.");
            }
        }).block(); 
    } catch (Exception e) {
        log.error("Error fetching from URL {}: {}", url, e.getMessage(), e);
        return null;
    }
}

试了ChatGPT给的各种方法都没解决,后来摸索出几个可行的方案,分享给你:

解决方案:绕过Spring的MediaType严格校验

问题根源在于Spring的MediaType类严格遵循RFC标准解析MIME类型,而WFS服务返回的subtype=gml/3.1.1里的斜杠不符合标准的token规则,所以我们需要跳过这个校验或者自定义解析逻辑。

方法1:自定义StringDecoder,直接读取响应体

我们可以给WebClient配置一个自定义的字符串解码器,不管响应的ContentType是什么,直接读取内容:

private static final WebClient webClient = WebClient.builder()
        .exchangeStrategies(ExchangeStrategies.builder()
                .codecs(configurer -> {
                    // 按需调整内存大小,避免大内容溢出
                    configurer.defaultCodecs().maxInMemorySize(16 * 1024 * 1024);
                    configurer.defaultCodecs().stringDecoder(new StringDecoder() {
                        @Override
                        public Mono<String> decodeToMono(ClientHttpResponse response, ResolvableType elementType,
                                                        @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
                            // 跳过MediaType校验,直接读取响应字节转字符串
                            return response.getBody()
                                    .map(dataBuffer -> {
                                        byte[] bytes = new byte[dataBuffer.readableByteCount()];
                                        dataBuffer.read(bytes);
                                        DataBufferUtils.release(dataBuffer);
                                        return new String(bytes, StandardCharsets.UTF_8);
                                    });
                        }
                    });
                })
                .build())
        .build();

方法2:使用exchange()手动处理响应

放弃使用retrieve()的自动解析,改用exchangeToMono()手动处理响应,这样就能绕过Spring的MediaType校验:

public static String fetchRemoteText(String url) {
    try {
        return webClient.get().uri(url)
                .exchangeToMono(response -> {
                    // 不管ContentType,直接把响应体转成字符串
                    return response.bodyToMono(String.class);
                })
                .doOnSuccess(body -> {
                    if (body == null || body.isBlank()) {
                        log.info("Empty result returned.");
                    }
                })
                .block();
    } catch (Exception e) {
        log.error("Error fetching from URL {}: {}", url, e.getMessage(), e);
        return null;
    }
}

方法3:注册自定义MediaType(更规范的方式)

如果希望Spring能识别这种非标准的MIME类型,可以注册一个自定义的MediaType,或者让字符串解码器接受所有text/xml的变种:

@Configuration
public class WebClientConfig {

    @Bean
    public WebClient webClient() {
        ExchangeStrategies strategies = ExchangeStrategies.builder()
                .codecs(configurer -> {
                    // 让字符串解码器接受所有text/xml相关的类型,包括带自定义参数的
                    configurer.customCodecs().register(new StringDecoder(MediaType.TEXT_XML, MediaType.ALL));
                })
                .build();

        return WebClient.builder()
                .exchangeStrategies(strategies)
                .build();
    }
}

总结

上面几个方法里,方法1和方法2比较直接,能快速解决问题;方法3更规范,但需要确保服务返回的类型在我们配置的范围内。你可以根据自己的项目情况选择合适的方案。

备注:内容来源于stack exchange,提问作者Loibologic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 09:34:34