当前位置: 首页 > news >正文

SpringCloudGateway集成SpringDoc CORS问题

SpringCloudGateway集成SpringDoc CORS问题

集成SpringDoc后,在gateway在线文档界面,请求具体的服务接口,报CORS问题

Failed to fetch.
Possible Reasons:
CORS
Network Failure
URL scheme must be “http” or “https” for CORS request.

分析

其实是网关直接请求具体服务/v3/api-docs接口(默认),获取文档数据,里面包含该服务注册上来的地址,gateway swagger-ui解析该接口数据,根据里面的地址直接请求。可是网关地址,跟具体的服务地址肯定不同源,在gateway集成界面请求,肯定报跨的问题。
或者是该微服务群,只能通过网关访问,直接请求具体的服务地址,网络不通。

{"openapi": "3.0.1","info": {"title": "XX服务","description": "XX服务开发接口文档","version": "1.0.0"},"servers": [{"url": "http://[2408:8456:601:9f52:225d:8f68:5e14:6ff4]:8201","description": "Generated server url"}]
}

思路

通过在gateway编写全局GatewayFilter,拦截集成时请求的 /xx/v3/api-docs接口(默认)接口,修改返回的数据,在servers写入通过网关直接访问的地址,就能解决在线文档请求接口,存在的跨域问题和网络不通问题。

实现

/*** 处理服务 /v3/api-docs接口返回的数据,在servers里添加可以通过网关直接访问的地址*/
@Slf4j
@Component
@ConditionalOnProperty(name = SPRINGDOC_ENABLED, matchIfMissing = true)
public class DocServiceUrlModifyGatewayFilter implements GlobalFilter, Ordered {@Autowiredprivate SpringDocConfigProperties springDocConfigProperties;@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//直接用配置类的值,默认值是 /v3/api-docsString apiPath = springDocConfigProperties.getApiDocs().getPath();ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();URI uri = request.getURI();//非正常状态跳过if (response.getStatusCode().value() != HttpStatus.OK.value()) {return chain.filter(exchange);}//非springdoc文档不拦截if (!(StringUtils.isNotBlank(uri.getPath()) && uri.getPath().endsWith(apiPath))) {return chain.filter(exchange);}String uriString = uri.toString();String gatewayUrl = uriString.substring(0, uriString.lastIndexOf(apiPath));DataBufferFactory bufferFactory = response.bufferFactory();ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(response) {@Overridepublic Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {//不处理if (!(body instanceof Flux)) {return super.writeWith(body);}//处理SpringDoc-OpenAPIFlux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;return super.writeWith(fluxBody.buffer().map(dataBuffers -> {DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();DataBuffer join = dataBufferFactory.join(dataBuffers);byte[] content = new byte[join.readableByteCount()];join.read(content);DataBufferUtils.release(join);try {// 流转为字符串String responseData = new String(content, StandardCharsets.UTF_8);Map<String, Object> map = JsonUtils.json2Object(responseData, Map.class);//处理返回的数据Object serversObject = map.get("servers");if (null != serversObject) {List<Map<String, Object>> servers = (List<Map<String, Object>>) serversObject;Map<String, Object> gatewayServer = new HashMap<>();//网关地址gatewayServer.put("url", gatewayUrl);gatewayServer.put("description", "Gateway server url");//添加到第1个servers.add(0, gatewayServer);map.put("servers", servers);responseData = JsonUtils.object2Json(map);byte[] uppedContent = responseData.getBytes(StandardCharsets.UTF_8);response.getHeaders().setContentLength(uppedContent.length);return bufferFactory.wrap(uppedContent);}} catch (Exception e) {log.error(e.getMessage(), e);}return bufferFactory.wrap(content);}));}};// replace response with decoratorreturn chain.filter(exchange.mutate().response(decoratedResponse).build());}@Overridepublic int getOrder() {return -2;}class JsonUtils {public static final ObjectMapper OBJECT_MAPPER = createObjectMapper();/*** 初始化ObjectMapper** @return*/private static ObjectMapper createObjectMapper() {ObjectMapper objectMapper = new ObjectMapper();objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);//        objectMapper.registerModule(new Hibernate4Module().enable(Hibernate4Module.Feature.FORCE_LAZY_LOADING));objectMapper.registerModule(new JavaTimeModule());return objectMapper;}public static String object2Json(Object o) {StringWriter sw = new StringWriter();JsonGenerator gen = null;try {gen = new JsonFactory().createGenerator(sw);OBJECT_MAPPER.writeValue(gen, o);} catch (IOException e) {throw new RuntimeException("不能序列化对象为Json", e);} finally {if (null != gen) {try {gen.close();} catch (IOException e) {throw new RuntimeException("不能序列化对象为Json", e);}}}return sw.toString();}/*** 将 json 字段串转换为 对象.** @param json  字符串* @param clazz 需要转换为的类* @return*/public static <T> T json2Object(String json, Class<T> clazz) {try {return OBJECT_MAPPER.readValue(json, clazz);} catch (IOException e) {throw new RuntimeException("将 Json 转换为对象时异常,数据是:" + json, e);}}}
}
http://www.lryc.cn/news/151235.html

相关文章:

  • 国际版阿里云/腾讯云:弹性高性能计算E-HPC入门概述
  • 【博客702】shell flock实现单例模式执行任务
  • 数据分析基础-数据可视化07-用数据分析讲故事
  • 策略模式简介
  • 学术加油站|基于端到端性能的学习型基数估计器综合测评
  • MySQL 使用规范 —— 如何建好字段和索引
  • Relation Extraction as Open-book Examination: Retrieval-enhanced Prompt Tuning
  • FFmpeg报错:Connection to tcp://XXX?timeout=XXX failed: Connection timed out
  • iOS开发Swift-7-得分,问题序号,约束对象,提示框,类方法与静态方法-趣味问答App
  • AUTOSAR规范与ECU软件开发(实践篇)7.10MCAL模块配置方法及常用接口函数介绍之Base与Resource的配置
  • Android11编译第二弹:USB连接MTP模式+USB调试+USB信任
  • Unity ShaderGraph教程——基础shader
  • 第 3 章 栈和队列(单链队列)
  • 【DFS】1254. 统计封闭岛屿的数目
  • C#--sugarClient使用之ColumnName
  • 深度学习-4-二维目标检测-YOLOv5源码测试与训练
  • 找不到msvcp140.dll的解决方法【msvcp140.dll修复工具下载】
  • 内网隧道代理技术(二十)之 CS使用HTTP代理上线不出网机器
  • 安卓 tcp 客户端
  • flutter plugins插件【三】【Flutter Intl】
  • 简单了解ICMP协议
  • MVCC究竟是什么?
  • Kafka知识点总结
  • K8s最基本概念
  • vulnhub渗透测试靶场练习2
  • 在R中安装TensorFlow、TensorFlow_Probability、numpy(R与Python系列第二篇)
  • 十大管理——项目成本管理
  • Java BIO、NIO、AIO学习总结
  • sql各种注入案例
  • 系统学习Linux-ELK日志收集系统