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

解决OpenAPI /v3/api-docs返回ASCII整数数组而非JSON的问题

解决OpenAPI /v3/api-docs返回ASCII数组问题

问题根源是自定义的GsonHttpMessageConverter被全局应用,导致SpringDoc的接口响应被错误序列化。以下是两种不影响自身API的解决方案:

方案一:限制自定义Gson转换器的适用路径

通过实现WebMvcConfigurer接口,让自定义转换器仅作用于你的业务API路径(比如/api/**),SpringDoc的/v3/api-docs路径则使用默认转换器处理。

修改后的配置类代码:

@Configuration
public class OpenApiConfiguration implements WebMvcConfigurer {

    @Bean
    public OpenAPI customOpenAPI() {
        return new OpenAPI().info(apiInfo());
    }

    private Info apiInfo() {
        return new Info()
                .title(API_INFO_TITLE)
                .description(API_INFO_DESC);
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 初始化自定义Gson配置
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.disableHtmlEscaping();
        gsonBuilder.registerTypeAdapter(Json.class, new SpringfoxjsonToGsonAdapter())
                .registerTypeAdapter(ChangeDriver.class, new InterfaceAdapter<CULayer>())
                .registerTypeAdapter(ChangeDriverData.class, new InterfaceAdapter<TxnCULayer>())
                .registerTypeAdapter(TriggerCU.class, new InterfaceAdapter())
                .registerTypeAdapter(ExtendedProperty.class, new InterfaceAdapter<ExtendedProperty>());

        GsonHttpMessageConverter customGsonConverter = new GsonHttpMessageConverter();
        customGsonConverter.setGson(gsonBuilder.create());

        // 添加带路径条件的转换器
        converters.add(new PathConditionalGsonConverter(customGsonConverter));
    }

    // 自定义条件转换器,仅对指定路径生效
    private static class PathConditionalGsonConverter extends GsonHttpMessageConverter {
        private final GsonHttpMessageConverter delegate;

        public PathConditionalGsonConverter(GsonHttpMessageConverter delegate) {
            this.delegate = delegate;
        }

        @Override
        public void write(Object object, Type type, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
            ServletRequestAttributes requestAttrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (requestAttrs != null) {
                String requestUri = requestAttrs.getRequest().getRequestURI();
                // 仅对业务API路径应用自定义转换器,根据实际路径调整
                if (requestUri.startsWith("/api/")) {
                    delegate.write(object, type, contentType, outputMessage);
                    return;
                }
            }
            // 非业务路径使用默认序列化逻辑
            super.write(object, type, contentType, outputMessage);
        }
    }

    private static class SpringfoxjsonToGsonAdapter implements JsonSerializer<Json> {
        @Override
        public JsonElement serialize(Json json, Type type, JsonSerializationContext context) {
            final JsonParser parser = new JsonParser();
            return parser.parse(json.value());
        }
    }
}

方案二:为SpringDoc单独配置Jackson转换器

如果你的业务API必须全局使用Gson,可以为SpringDoc的接口单独指定Jackson转换器(Spring默认的JSON处理工具):

@Configuration
public class OpenApiConfiguration {

    @Bean
    public OpenAPI customOpenAPI() {
        return new OpenAPI().info(apiInfo());
    }

    private Info apiInfo() {
        return new Info()
                .title(API_INFO_TITLE)
                .description(API_INFO_DESC);
    }

    @Bean
    public GsonHttpMessageConverter getMessGsonHttpMessageConverter(GsonBuilder gsonBuilder) {
        GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
        gsonBuilder.disableHtmlEscaping();
        gsonBuilder.registerTypeAdapter(Json.class, new SpringfoxjsonToGsonAdapter())
                .registerTypeAdapter(ChangeDriver.class, new InterfaceAdapter<CULayer>())
                .registerTypeAdapter(ChangeDriverData.class, new InterfaceAdapter<TxnCULayer>())
                .registerTypeAdapter(TriggerCU.class, new InterfaceAdapter())
                .registerTypeAdapter(ExtendedProperty.class, new InterfaceAdapter<ExtendedProperty>());
        converter.setGson(gsonBuilder.create());
        return converter;
    }

    // 为SpringDoc路径配置Jackson转换器
    @Bean
    public WebMvcConfigurer springDocJacksonConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
                configurer.favorPathExtension(false);
            }

            @Override
            public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
                MappingJackson2HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter();
                converters.add(0, new SpringDocConditionalJacksonConverter(jacksonConverter));
            }
        };
    }

    private static class SpringDocConditionalJacksonConverter extends MappingJackson2HttpMessageConverter {
        private final MappingJackson2HttpMessageConverter delegate;

        public SpringDocConditionalJacksonConverter(MappingJackson2HttpMessageConverter delegate) {
            this.delegate = delegate;
        }

        @Override
        public boolean canWrite(Class<?> clazz, MediaType mediaType) {
            ServletRequestAttributes requestAttrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (requestAttrs != null) {
                String requestUri = requestAttrs.getRequest().getRequestURI();
                // 仅对SpringDoc接口路径使用Jackson
                return requestUri.startsWith("/v3/api-docs") && delegate.canWrite(clazz, mediaType);
            }
            return false;
        }
    }

    private static class SpringfoxjsonToGsonAdapter implements JsonSerializer<Json> {
        @Override
        public JsonElement serialize(Json json, Type type, JsonSerializationContext context) {
            final JsonParser parser = new JsonParser();
            return parser.parse(json.value());
        }
    }
}

关键说明

  • 不要使用@EnableWebMvc,它会完全覆盖Spring MVC的默认配置,导致业务API的序列化逻辑被破坏。
  • 通过实现WebMvcConfigurer接口添加自定义配置,只会补充而非替换默认规则,能保证原有业务API不受影响。

内容的提问来源于stack exchange,提问作者virot

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 01:57:49