SpringCloud+Vue+Python人工智能(fastAPI,机器学习,深度学习)前后端架构各功能实现思路——SpringCloud后端——Gateway网关

SpringCloud+Vue+Python人工智能(fastAPI,机器学习,深度学习)前后端架构各功能实现思路——主目录(持续更新):https://blog.csdn.net/grd_java/article/details/144986730

1. spring boot启动类

gateway网关也是一个springboot项目


在这里插入图片描述

package com.yd_oa_java_cloud.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//启动类,springIOC容器加载时 扫描的包范围为com.yd_oa_java_cloud,主要要将你想要spring管理的包都放在一个固定路径下
//我们写代码时,经常创建包搞一个什么com.XXXXX.XXXXX,然后配置时就用com.XXXXX
@SpringBootApplication(scanBasePackages = {"com.yd_oa_java_cloud"})
public class YdOaCloudGatewayRunApplication {
    public static void main(String[] args) {
        SpringApplication.run(YdOaCloudGatewayRunApplication.class,args);
    }
}

2. gateway配置文件,和nacos配置中心的配置文件

1. 代码中,resources文件夹中创建bootstrap.yml文件(注意文件名不可以随便定义,必须是这个),注意配置中,服务名,不可以有下划线


在这里插入图片描述

spring:
  profiles:
    active: dev #定义环境为开发环境
  application:
    name: yd-oa-java-gateway # 服务名字,服务之间相互调用都依赖这个名字
  # spring cloud相关配置
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 # localhost:8848为默认的nacos本地端口位置
      config:
        server-addr: 127.0.0.1:8848 # 配置中心地址
        file-extension: yml # 配置中心的文件后缀类型
        # 配置中心要加载的yml文件名为yd_oa_java_gateway-dev.yml这样式的,也就是服务名-环境.后缀
        shared-configs: ${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} # 对应nacos配置中心的Data Id

2. nacos配置中心添加


在这里插入图片描述


在这里插入图片描述


feign:
    okhttp:
        enabled: true #feign组件,这里gateway可以不用配置
server:
    port: 7071 # 当前服务端口号

# 日志放置的路径和级别
project:
    folder: E:/webser/yd_oa_cloud/ 
log:
    root:
        level: debug

3. 启动测试

1. 启动gateway网关


在这里插入图片描述


2. nacos成功注册项目


在这里插入图片描述


3. 用随便一个模块测试一下,例如Spring Security模块,具体构建方式可以参考:https://blog.csdn.net/grd_java/article/details/145013189


4. 写一个测试方法


在这里插入图片描述


5. 此时请求7072端口的接口可以请求到,但是我们有网关的目的是统一请求网关所在的7071端口才对,反而,请求7071是无法请求到的


在这里插入图片描述


在这里插入图片描述

4. 路由配置

添加路由相关配置


在这里插入图片描述

spring:
  cloud:
    gateway:
      discovery: # 可以不配置
        locator:
          enabled: true #使用服务发现路由=true,依赖于openfeign
          lower-case-service-id: true #服务名路由可以小写
      routes:
        - id: yd-oa-java-security #路由id ,随便起,推荐写服务名
          uri: lb://yd-oa-java-security #lb是负载均衡,路由url,lb:// 后面 要写在nacos中注册的名字,因为我配置了服务名路由可以小写,所以这里小写也没关系
          predicates:
            - Path=/security/** # 路径断言匹配,和nginx中配置转发差不多,就是遇到这个路径的请求,转发到yd_oa_java_security这个服务去处理
          filters:
            - StripPrefix=1 # Path中只过滤第一段路径,也就是我们请求时只需要遇到/security这个路径,就转发

此时我们配置了/security/**路径的请求全部通过lb负载均衡的模式,分发到yd-oa-java-security这个服务对应的实例集群中处理


此时我们可以通过请求gateway网关地址/配置中Path对应路径/具体要请求的路径,来通过网关分发到具体服务请求接口


在这里插入图片描述

当我们某个服务的多个实例,其中有一台挂掉时,并不能立即处理,gateway依旧会将部分请求负载均衡到这个已经挂掉的实例上


通常它需要十几秒的时间才能注意到有一台已经挂掉了,放弃将请求分发到它身上。此时就需要配置熔断,全局的异常处理,后面会介绍到

nginx也可以分发负载均衡,但是它不能渗透到业务中,gateway可以做代码中的健全


所以一般会外层使用nginx,它确实十分强大,然后内层有一层gateway网关,然后才是具体业务模块

5. 过滤器

5.1 全局过滤器配置方法

1. 全局过滤器(全局拦截器),主要用于防xss注入(跨站脚本攻击,通过漏洞注入恶意代码)、以及登录的拦截等,所有的请求都会进行过滤


在这里插入图片描述

代码中只是演示了过滤器的配置方法,输出了一个日志。之后如何使用,还取决于具体业务功能需要,目前只是配置一个网关,还不需要编写过滤器,之后进行登录鉴权时,才会使用


package com.yd_oa_java_cloud.gateway.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * gateway 全局过滤器,可以调用spring Security微服务进行鉴权
 * implements GlobalFilter 实现GlobalFilter接口,实现全局过滤器。可以有多个
 * implements Ordered 实现过滤器的先后顺序,如果有多个过滤器,通过此接口规定每个过滤器的先后顺序
 */
@Component//组件组成,交由SpringIOC容器管理
@Slf4j //日志
public class GateWayGlobalRequestFilter implements GlobalFilter , Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String rawPath = exchange.getRequest().getURI().getRawPath();//获取请求路径
        log.info("GateWayGlobalRequestFilter:"+rawPath);
        //过滤完成,可以向下传递
        return chain.filter(exchange);
    }
    //定义此过滤器为所有过滤器的第0层过滤器
    @Override
    public int getOrder() {
        return 0;
    }
}

2. 测试,访问security的测试接口


在这里插入图片描述


getaway成功过滤,并放行


在这里插入图片描述

5.2 指定过滤器配置方法

1. 只过滤部分请求的过滤器为指定过滤器,只需要配置路由时为其指定过滤器即可。一般应用在包含前后台系统的网站,后台系统需要鉴权,而前台系统很多内容是只要进入网站就可以观看的,无需登录认证。


2. 例如为Security请求添加指定过滤器,只需要在filters配置下添加指定过滤器即可


在这里插入图片描述

spring:
  cloud:
    gateway:
      routes:
        - id: yd-oa-java-security #路由id ,随便起,推荐写服务名
          uri: lb://yd-oa-java-security #lb是负载均衡,路由url,lb:// 后面 要写在nacos中注册的名字,因为我配置了服务名路由可以小写,所以这里小写也没关系
          predicates:
            - Path=/security/** # 路径断言匹配,和nginx中配置转发差不多,就是遇到这个路径的请求,转发到yd_oa_java_security这个服务去处理
          filters:
            - StripPrefix=1 # Path中只过滤第一段路径,也就是我们请求时只需要遇到/security这个路径,就转发
            - SecurityRequestFilter # 这个路由的指定过滤器

3. 和全局过滤器不同的是,指定过滤器需要继承AbstractGatewayFilterFactory类


在这里插入图片描述

package com.yd_oa_java_cloud.gateway.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;

@Component //交由spring IOC管理
@Slf4j
public class SecurityRequestFilter extends AbstractGatewayFilterFactory {

    @Override
    public GatewayFilter apply(Object config) {
        return ((exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            String rawPath = request.getURI().getRawPath();
            log.info("SecurityRequestFilter:@TODO:登录相关认证操作,{}",rawPath);
            return chain.filter(exchange);
        });
    }
}

4. 请求测试


在这里插入图片描述


在这里插入图片描述

5.3 不推荐使用过滤器的场景

当某个服务中部分路径需要鉴权,而部分路径可以直接放行时,通过过滤器只能通过路径去判断


此时,AOP切面是个更好的选择

6. 全局异常处理(全局拦截器Handler)

注意,全局异常拦截器是针对Gateway的,如果请求成功路由到对应微服务,然后微服务中出错,就不是这个拦截器的管理范围了


我们以404为例,我们的路由配置路径为security路径分发到权限微服务处理。那么如果我们输入security1这个路径,就没有对应可以路由的微服务,一定会报gateway网关层面的404


在这里插入图片描述


但是如果我们就是输入security路径,那么gateway根据我们的配置会成功路由到权限服务中处理。此时权限服务中的路径输入错误,和gateway网关就没有什么关系了。下面的例子中,我们路由地址填写正确,但是具体微服务接口填写错误,就不会触发拦截器


在这里插入图片描述

实现方法也很简单,只需要实现WebExceptionHandler接口即可,但是要注意,异常拦截器应该在所有过滤器之前执行,也就是说需要额外添加注解@Order(-1)(视情况改变,值越小越先执行,如果你的项目中-1不是最小,那么就改为更小的值)


在这里插入图片描述


package com.yd_oa_java_cloud.gateway.handler;

import com.yd_oa_java_cloud.base.entity.enums.ResponseCodeEnum;
import com.yd_oa_java_cloud.base.entity.vo.ResponseVO;
import com.yd_oa_java_cloud.base.exception.BusinessException;
import com.yd_oa_java_cloud.base.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
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;

import java.nio.charset.StandardCharsets;

/**
 * 全局异常拦截器
 */
@Slf4j
@Component
@Order(-1) //异常拦截器应该在其它过滤器之前执行
public class GatewayExceptionHandler implements WebExceptionHandler {
    protected static final String STATUS_ERROR = "error";//错误状态信息
    //WebExceptionHandler 拦截处理逻辑
    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        ResponseVO responseVO = getResponse(ex);//获取异常信息,返回结果为封装好的ResponseVO对象

        ServerHttpResponse response = exchange.getResponse();//获取响应体对象
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);//设置响应头上下文类型为Json
        //获取异常信息json流
        DataBuffer dataBuffer = response.bufferFactory().wrap(JsonUtils.convertObjToJson(responseVO).getBytes(StandardCharsets.UTF_8));
        //将其写到响应体中
        return response.writeWith(Mono.just(dataBuffer));
    }

    /**
     * 自定义方法,获取异常信息
     * @param ex
     * @return
     */
    private ResponseVO getResponse(Throwable ex){
        ResponseVO responseVO = new ResponseVO();
        //设置错误状态
        responseVO.setStatus(STATUS_ERROR);
        //如果响应的错误属于ResponseStatusException的实例
        if (ex instanceof ResponseStatusException){
            ResponseStatusException responseStatusException = (ResponseStatusException) ex;//错误强转
            //如果错误就是404错误的话
            if (HttpStatus.NOT_FOUND == responseStatusException.getStatus()){
                //将我们封装的响应枚举类中封装的信息进行响应
                responseVO.setCode(ResponseCodeEnum.CODE_404.getCode());
                responseVO.setInfo(ResponseCodeEnum.CODE_404.getMsg());
                return responseVO;
            }
            //如果是应用服务(微服务)不可用的话。当要路由的微服务挂掉的话,会报此错误
            else if (HttpStatus.SERVICE_UNAVAILABLE == responseStatusException.getStatus()){
                responseVO.setCode(ResponseCodeEnum.CODE_503.getCode());
                responseVO.setInfo(ResponseCodeEnum.CODE_503.getMsg());
                return responseVO;
            }
            //其余异常
            else{
                responseVO.setCode(responseStatusException.getStatus().value());
                responseVO.setInfo(ResponseCodeEnum.CODE_500.getMsg());
                return responseVO;
            }
        }
        //如果是我们自定义异常的话
        else if(ex instanceof BusinessException){
            BusinessException businessException = (BusinessException) ex;
            responseVO.setCode(businessException.getCode());
            responseVO.setInfo(businessException.getMessage());
            return responseVO;
        }
        //如果是未知错误,报500
        responseVO.setCode(ResponseCodeEnum.CODE_500.getCode());
        responseVO.setInfo(ResponseCodeEnum.CODE_500.getMsg());
        return responseVO;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ydenergy_殷志鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值