SpringCloudGateway集成SpringDoc CORS问题

这篇具有很好参考价值的文章主要介绍了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写入通过网关直接访问的地址,就能解决在线文档请求接口,存在的跨域问题和网络不通问题。文章来源地址https://www.toymoban.com/news/detail-693409.html

实现

/**
 * 处理服务 /v3/api-docs接口返回的数据,在servers里添加可以通过网关直接访问的地址
 */
@Slf4j
@Component
@ConditionalOnProperty(name = SPRINGDOC_ENABLED, matchIfMissing = true)
public class DocServiceUrlModifyGatewayFilter implements GlobalFilter, Ordered {
    @Autowired
    private SpringDocConfigProperties springDocConfigProperties;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //直接用配置类的值,默认值是 /v3/api-docs
        String 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) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                //不处理
                if (!(body instanceof Flux)) {
                    return super.writeWith(body);
                }

                //处理SpringDoc-OpenAPI
                Flux<? 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 decorator
        return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }

    @Override
    public 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);
            }
        }


    }
}

到了这里,关于SpringCloudGateway集成SpringDoc CORS问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • spring cloud gateway跨域配置CORS Configuration

    表象看:浏览器上的 IP,域名,端口 和你页面内请求的IP,域名,端口 之间组合不一致。这说法不够严谨,但不是本文的重点,更多概念自行检索。 spring-cloud-gateway3.x.x为例 官方说明 Spring Cloud Gateway 配置参数说明:CorsConfiguration (Spring Framework 5.0.20.RELEASE API)    附中文文档说明

    2024年02月13日
    浏览(42)
  • Spring Cloud Gateway系例—参数配置(CORS 配置、SSL、元数据)

    你可以配置网关来控制全局或每个路由的 CORS 行为。两者都提供同样的可能性。 “global” CORS配置是对 Spring Framework CorsConfiguration 的URL模式的映射。下面的例子配置了 CORS。 Example 77. application.yml 在前面的例子中,对于所有GET请求的路径,允许来自 docs.spring.io 的请求的CORS请求

    2024年02月13日
    浏览(49)
  • Spring Cloud Gateway集成Nacos实现负载均衡

    💡Nacas可以用于实现Spring Cloud Gateway中网关动态路由功能,也可以基于Nacos来实现对后端服务的负载均衡,前者利用Nacos配置中心功能,后者利用Nacos服务注册功能。 接下来我们来看下Gateway集成Nacos实现负载均衡的架构图 一. 环境准备 1. 版本环境 Jdk: java.version1.8/java.version Spr

    2024年02月10日
    浏览(54)
  • Spring Cloud Gateway集成sentinel进行网关限流

    本文使用版本如下:

    2024年02月09日
    浏览(48)
  • Spring Cloud Gateway集成Nacos作为注册中心和配置中心

    本篇文章将介绍Spring Cloud Alibaba体系下Spring Cloud Gateway的搭建,服务注册中心和分布式配置中心使用Nacos,后续将会持续更新,介绍集成Sentinel,如何做日志链路追踪,如何做全链路灰度发布设计,以及Spring Cloud Gateway的扩展等。 ​ Spring Boot,Spring Cloud,Discovery,Config等基础依

    2024年02月11日
    浏览(97)
  • Spring Cloud Gateway集成Sentinel 1.8.6及Sentinel Dashboard

    一、安装sentinel 1.下载地址:sentinel v1.8.6 2.启动sentinel dashboard,执行以下命令: java -Dcsp.sentinel.log.dir=D:xxxsentinellogs -Dserver.port=9217 -Dcsp.sentinel.dashboard.server=localhost:9217 -Dcsp.sentinel.heartbeat.client.ip=localhost -Dproject.name=sentinel-dashboard -Dsentinel.dashboard.auth.username=sentinel -Dsentinel.dashboar

    2024年02月11日
    浏览(48)
  • Spring Cloud Gateway集成Actuator的安全漏洞和解决方案

    Spring Cloud Gateway是一个基于Spring Boot2.0和Spring WebFlux的API网关,它可以将请求转发到多个微服务并对请求进行路由、过滤和修改。Spring Cloud Gateway集成Actuator后可以提供更多的监控和管理功能,但是也可能导致安全漏洞。 最近线上环境出现一起安全事件,就是由于Spring Cloud Gat

    2024年02月09日
    浏览(47)
  • Spring Cloud Gateway集成Swagger实现微服务接口文档统一管理及登录访问

    本文将介绍如何在 Spring Cloud 微服务中使用 Swagger 网关来统一管理所有微服务的接口文档,并通过 Spring Security 实现登录后才能访问 Swagger 文档,以确保接口数据的安全访问。 在开始之前,需要假设你已经完成了 Spring Cloud Gateway 的相关配置,并且已经了解了基本的网关配置知

    2024年02月05日
    浏览(42)
  • @Tag和@Operation标签失效问题。SpringDoc 2.2.0(OpenApi 3)和Spring Boot 3.1.1集成

    问题 @Tag和@Operation标签失效 但是@Schema标签有效 pom依赖 debug排查,发现时国际化问题 解决方法:application.yml配置禁用i18n翻译

    2024年02月05日
    浏览(55)
  • Spring Cloud Gateway集成聚合型Spring Boot API发布组件knife4j,增强Swagger

    大家都知道,在前后端分离开发的时代,前后端接口对接是一项必不可少的工作。 可是, 作 为后端开发,怎么和前端更好的配合,才能让自己不心累、脑累 ,直接扔给前端一个后端开放api接口文档或者页面,让前端不用看着难受,也不用前端老问你,来愉快的合作呢? 原

    2024年04月22日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包