网关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才能正常访问。

相关推荐
一嘴一个橘子43 分钟前
mybatis - 动态语句、批量注册mapper、分页插件
java
组合缺一44 分钟前
Json Dom 怎么玩转?
java·json·dom·snack4
危险、1 小时前
一套提升 Spring Boot 项目的高并发、高可用能力的 Cursor 专用提示词
java·spring boot·提示词
kaico20181 小时前
JDK11新特性
java
钊兵1 小时前
java实现GeoJSON地理信息对经纬度点的匹配
java·开发语言
jiayong231 小时前
Tomcat性能优化面试题
java·性能优化·tomcat
秋刀鱼程序编程1 小时前
Java基础入门(五)----面向对象(上)
java·开发语言
纪莫2 小时前
技术面:MySQL篇(InnoDB的锁机制)
java·数据库·java面试⑧股
Remember_9932 小时前
【LeetCode精选算法】滑动窗口专题二
java·开发语言·数据结构·算法·leetcode
Filotimo_2 小时前
在java开发中,cron表达式概念
java·开发语言·数据库