zoukankan      html  css  js  c++  java
  • gateway 网关(转发,跨域,拦截器等)

    1,所需依赖

    <!-- 网关依赖 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    

    2,配置路径映射

    spring:
      cloud:
        gateway:
          discovery:
            locator:
              # 开启项目名称映射功能,即通过服务名访问项目,不需要写明具体IP地址
              enabled: true
              # 请求路由全部转小写字母,如 Aa/Bb 会被转为 aa/bb
              lower-case-service-id: true
          routes:
              # 路由规则的唯一标识,任意齐名,建议和服务名一致
            - id: sc-web-admin-back
              # 转发到的节点,lb:// 为 http,lb:ws:// 为 websocket
              uri: lb://sc-web-admin-back/
              predicates:
                  # 断言规则,这里设置匹配的路由规则
                - Path=/admin-back/**
              # 过滤规则
              filters:
                # 转发到具体项目去掉路由首单词,如 /admin-back/a 转发为 /a
                - StripPrefix=1
    

    如上,便配置了一个接管以 admin-back 开头的路由,并转发给项目 sc-web-admin-back

    3,跨域配置

    spring:
      cloud:
        gateway:
          globalcors:
            # 全局允许跨域访问
            cors-configurations:
              '[/**]':
                allow-credentials: true
                allowed-origins: "*"
                allowed-headers: "*"
                allowed-methods:
                  - OPTIONS
                  - GET
                  - POST
                  - PUT
                  - DELETE
    

    4,全局异常处理

    日常开发中,我们难免会有忘记处理的异常,程序也很难保重不出错,这时候我们就需要一个能够全局捕捉异常的功能来未我们兜底,防止错误被用户看到影响体验

    package com.hwq.gateway.handler;
    
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.hwq.gateway.vo.ResultVO;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Primary;
    import org.springframework.core.Ordered;
    import org.springframework.core.annotation.Order;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.server.reactive.ServerHttpResponse;
    import org.springframework.stereotype.Component;
    import org.springframework.web.server.ResponseStatusException;
    import org.springframework.web.server.ServerWebExchange;
    import org.springframework.web.server.WebExceptionHandler;
    import reactor.core.publisher.Mono;
    
    @Component
    @Primary   // 同类型带有该注解的 Bean 优先背识别
    @Order(Ordered.HIGHEST_PRECEDENCE)
    @Slf4j
    public class JsonExceptionHandler implements WebExceptionHandler {
    
        @Autowired
        private ObjectMapper objectMapper;
    
        /**
         * 所有异常都会在这里被集中处理
         * @param exchange 上下文
         * @param ex       异常
         * SuppressWarnings("NullableProblems"):屏蔽 @NonNullApi 的警告
         */
        @Override
        @SuppressWarnings("NullableProblems")
        public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
            ServerHttpResponse response = exchange.getResponse();
            ResultVO<Object> vo;
            if (ex instanceof ResponseStatusException && ((ResponseStatusException) ex).getStatus() == HttpStatus.NOT_FOUND) {
                vo = ResultVO.fail("当前访问的地址不存在,请修改后重试!");
            } else {
                vo = ResultVO.error(ex.getMessage());
            }
            return response.writeWith(Mono.fromSupplier(() -> {
                byte[] bytes;
                try {
                    bytes = objectMapper.writeValueAsBytes(vo);
                } catch (JsonProcessingException e) {
                    response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
                    bytes = "JSON 转换异常!".getBytes();
                }
                return response.bufferFactory().wrap(bytes);
            }));
        }
    
    }
    

    5,捕获转发项目传来的异常

    上面的类只能捕捉网关本身发生的异常,而如果其调用(转发)的项目发生异常,返回错误时不能拦截,这时候我们就需要一个过滤器,能把哪些错误的返回拦截掉,并触发上面全局异常处理

    package com.hwq.gateway.filter;
    
    import org.reactivestreams.Publisher;
    import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    import org.springframework.cloud.gateway.filter.GlobalFilter;
    import org.springframework.core.Ordered;
    import org.springframework.core.io.buffer.DataBuffer;
    import org.springframework.core.io.buffer.DataBufferUtils;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.server.reactive.ServerHttpResponse;
    import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
    import org.springframework.stereotype.Component;
    import org.springframework.web.server.ResponseStatusException;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Flux;
    import reactor.core.publisher.Mono;
    
    import java.nio.charset.StandardCharsets;
    
    @Component
    public class ExceptionFilter implements Ordered, GlobalFilter {
    
        /**
         * 如果需要拦截返回值并处理,这里则需要返回负数
         */
        @Override
        public int getOrder() {
            return -1;
        }
    
        /**
         * 异常拦截,拦截响应值不是 200 的数据,并抛给全局异常处理
         */
        @Override
        @SuppressWarnings({"unchecked", "NullableProblems"})
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            ServerHttpResponse response = exchange.getResponse();
            ServerHttpResponseDecorator decorated = new ServerHttpResponseDecorator(response) {
                @Override
                public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                    if (body instanceof Flux) {
                        Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                        return super.writeWith(fluxBody.map(dataBuffer -> {
                            if (response.getStatusCode() == HttpStatus.NOT_FOUND) {
                                throw new ResponseStatusException(HttpStatus.NOT_FOUND);
                            }
                            if (response.getStatusCode() != HttpStatus.OK) {
                                byte[] content = new byte[dataBuffer.readableByteCount()];
                                dataBuffer.read(content);
                                DataBufferUtils.release(dataBuffer); // 释放掉内存
                                String errMsg = new String(content, StandardCharsets.UTF_8);
                                throw new RuntimeException(errMsg);
                            }
                            return dataBuffer;
                        }));
                    }
                    return super.writeWith(body);
                }
            };
            return chain.filter(exchange.mutate().response(decorated).build());
        }
    
    }
    

    6,普通的拦截器

    package com.hwq.gateway.filter;
    
    import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    import org.springframework.cloud.gateway.filter.GlobalFilter;
    import org.springframework.core.Ordered;
    import org.springframework.http.server.reactive.ServerHttpRequest;
    import org.springframework.http.server.reactive.ServerHttpResponse;
    import org.springframework.stereotype.Component;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Mono;
    
    @Component
    public class UserFilter implements Ordered, GlobalFilter {
    
        /**
         * 这里的返回值决定拦截器的优先级,数字越小越先被触发,支持负数
         */
        @Override
        public int getOrder() {
            return 1;
        }
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
            // 这里可以获取 请求对象 和 响应对象
            ServerHttpRequest request = exchange.getRequest();
            ServerHttpResponse response = exchange.getResponse();
    
            // 逻辑处理
            
    
            // 逻辑处理
    
            // 传递给下一级别的过滤器
            return chain.filter(exchange);
        }
    }
    
  • 相关阅读:
    第四天 PYTHON 函数
    第四天 PYTHON 字符串格式化
    第四天 PYTHON 集合
    Linux使用sshfs挂载远程目录到本地
    linux通过安装包安装nginx和jdk
    使用ajax提交form表单,包括ajax文件上传
    Linux下mysql出错:ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
    数据库连接池
    一台机器上安装两个tomcat
    mysql优化
  • 原文地址:https://www.cnblogs.com/lovling/p/14174796.html
Copyright © 2011-2022 走看看