解决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
相关产品推荐
相关产品推荐

