网关gateway

网关gateway

含义与作用

在Java微服务开发中,gateway网关是一个用来处理客户端请求和微服务之间通信的中间层。它常常被用作微服务架构的入口点,负责将外部的请求路由到不同的微服务上。

gateway网关的主要用处包括以下几个方面:

  1. 路由转发:gateway网关可以根据请求的URL路径、请求方法、请求头等信息,将请求动态地路由到对应的微服务上。通过路由规则的配置,可以实现请求的负载均衡和故障转移,提高系统的可用性和稳定性。

  2. 服务聚合:在微服务架构中,一个页面可能需要调用多个微服务才能完成。gateway网关可以聚合多个微服务的接口,组合成一个统一的API,对外提供服务。这样,客户端只需请求一次gateway网关的接口,而无需直接调用多个微服务接口,简化了客户端的请求过程。

  3. 安全控制:gateway网关可以集中处理安全认证和授权,对请求进行身份验证、权限校验等操作。它可以维护用户会话、生成和验证Token,确保只有授权的请求才能访问微服务。

  4. 限流和熔断:gateway网关可以通过限制每个微服务的请求频率、并发数等方式,对请求进行限流。同时,它也可以实现熔断机制,当某个微服务发生故障或超时时,自动拦截请求,避免对整个系统造成雪崩效应。

  5. 日志和监控:gateway网关可以集中收集请求日志,记录请求的详细信息,便于后续的审计和故障排查。同时,它也可以对请求进行监控和统计,提供实时的性能指标和错误报警。

总结:gateway网关在Java微服务开发中扮演着重要的角色,它能够为微服务提供路由转发、服务聚合、安全控制、限流和熔断、日志和监控等功能,提高系统的可用性、性能和安全性。

使用

(1)在kaihe-leadnews-gateway(管理所有网关的微服务)导入以下依赖

pom文件

xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
     <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
    </dependency>
</dependencies>

(2)在kaihe-leadnews-gateway下创建kaihe-leadnews-app-gateway微服务(子网关,某一大块业务的网关,如app端的网关)

引导类:

java 复制代码
//就是将这个maven项目改成springboot项目,如果新建的kaihe-leadnews-app-gateway项目就是springboot项目,这一块引导类就不用添加,只需添加下面的配置就行了
package com.heima.app.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient  //开启注册中心
public class AppGatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(AppGatewayApplication.class,args);
    }
}

bootstrap.yml

yaml 复制代码
server:
  port: 51601
spring:
  application:
    name: leadnews-app-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.200.130:8848
      config:
        server-addr: 192.168.200.130:8848
        file-extension: yml

在nacos的配置中心创建dataid为leadnews-app-gateway的yml配置

如下图所示:

yaml 复制代码
spring:
  cloud:
    gateway:
      globalcors: # 过滤请求的配置
        add-to-simple-url-handler-mapping: true # 将该gateway网关添加到Spring MVC中的URL处理映射中
        corsConfigurations:
          '[/**]': # 匹配所有请求
            allowedHeaders: "*" # 允许所有请求头的请求
            allowedOrigins: "*" # 跨域处理,允许所有的域
            allowedMethods: # 允许的请求方法
              - GET
              - POST
              - DELETE
              - PUT
              - OPTION
      routes: # 路由请求的配置
        # 平台管理
        - id: user # 路由规则的唯一标识符
          uri: lb://leadnews-user # 路由请求的目标地址,表示负载均衡请求到名为 leadnews-user 的微服务
          predicates:  # 匹配请求的条件
            - Path=/user/** # 表示只有请求路径以 /user/ 开头的请求才会被路由到该微服务。
          filters: # 在路由过程中对请求进行过滤处理的操作
            - StripPrefix= 1 # 表示过滤掉请求路径的前缀 /user/,以便目标微服务能够正确处理请求
          
          # 总结起来,上述路由的这段配置的作用是将以 /user/ 开头的请求路由到名为 leadnews-user 的微服务,并且去除请求路径中的前缀 /user/

环境搭建完成以后,启动项目网关和用户两个服务,使用postman进行测试

请求地址:http://localhost:51601/user/api/v1/login/login_auth

这里要注意,请求路径中IP端口后后面加了个user,而登录的controller和接口上是没有定义user的,就是因为加了gateway网关的路由请求的配置predicates:- Path=/user/**,所以要加上前缀/user/才会被路由到leadnews-user这个微服务,但通过网关之后,因为加了filters: - StripPrefix=1这个配置,请求路径中的/user/前缀就会被去掉,就变成了http://localhost:51601/api/v1/login/login_auth,所以能够访问到leadnews-user上的登录接口。

gateway路由请求就完成了,可以启动项目网关和用户两个服务,用postman访问http://localhost:51601/user/api/v1/login/login_auth来测试登录接口了。

1.3 全局过滤器实现jwt校验

思路分析:

  1. 用户进入网关开始登陆,网关过滤器进行判断,如果是登录,则路由到后台管理微服务进行登录
  2. 用户登录成功,后台管理微服务签发JWT TOKEN信息返回给用户
  3. 用户再次进入网关开始访问,网关过滤器接收用户携带的TOKEN
  4. 网关过滤器解析TOKEN ,判断是否有权限,如果有,则放行,如果没有则返回未认证错误

具体实现:

第一:

​ 在认证过滤器中需要用到jwt的解析,所以需要把工具类AppJwtUtil拷贝一份到网关微服务

第二:

在网关微服务中新建全局过滤器:

java 复制代码
package com.kaihe.app.gateway.filter;


import com.kaihe.app.gateway.util.AppJwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
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
@Slf4j
public class AuthorizeFilter implements Ordered, GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1.获取request和response对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        //2.判断是否是登录
        if(request.getURI().getPath().contains("/login")){
            //放行
            return chain.filter(exchange);
        }


        //3.获取token
        String token = request.getHeaders().getFirst("token");

        //4.判断token是否存在
        if(StringUtils.isBlank(token)){
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }

        //5.判断token是否有效
        try {
            Claims claimsBody = AppJwtUtil.getClaimsBody(token);
            //是否是过期
            int result = AppJwtUtil.verifyToken(claimsBody);
            if(result == 1 || result  == 2){
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                return response.setComplete();
            }
        }catch (Exception e){
            e.printStackTrace();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }

        //6.放行
        return chain.filter(exchange);
    }

    /**
     * 过滤器的优先级设置,值越小,优先级越高
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

测试:

启动user服务,继续访问其他微服务,会提示需要认证才能访问,这个时候需要在heads中设置设置token才能正常访问。

相关推荐
suweijie7683 小时前
SpringCloudAlibaba | Sentinel从基础到进阶
java·大数据·sentinel
公贵买其鹿3 小时前
List深拷贝后,数据还是被串改
java
xlsw_7 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹7 小时前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭8 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫8 小时前
泛型(2)
java
超爱吃士力架8 小时前
邀请逻辑
java·linux·后端
南宫生8 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石8 小时前
12/21java基础
java
李小白668 小时前
Spring MVC(上)
java·spring·mvc