Java之api网关断言及过滤器案例讲解

网友投稿 293 2022-12-20

Java之api网关断言及过滤器案例讲解

目录一、什么是api网关?二、常见的api网关三、使用步骤1.Spring Cloud Gateway2.优缺点3.传统的过滤器4.使用gateway4.1module4.2添加pom依赖4.3yaml配置4.4主程序开启注解@EnableDiscoveryClient四、执行流程五、断言5.1: 自定义断言5.2: 过滤器

一、什么是api网关?

所谓的API网关,就是指后台系统的统一入口,它封装了应用程序的内部结构,为客户端提供统一 路由服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、路由转发等等。

说白了就是通过网关找服务。

二、常见的api网关

Ngnix+lua

使用nginx的反向代理和负载均衡可实现对api服务器的负载均衡及高可用lua是一种脚本语言,可以来编写一些简单的逻辑, nginx支持lua脚本Kong

基于Nginx+Lua开发,性能高,稳定,有多个可用的插件(限流、鉴权等等)可以开箱即用。问题:只支持Http协议;二次开发,自由扩展困难;提供管理API,缺乏更易用的管控、配置方式。

Zuul Netflix开源的网关,功能丰富,使用java开发,易于二次开发问题:缺乏管控,无法动态配置;依赖组件较多;处理Http请求依赖的是Web容器,性能不如Nginx

Spring Cloud Gateway

Spring公司为了替换Zuul而开发的网关服务,将在下面具体介绍。

三、使用步骤

1.Spring Cloud Gateway

Spring Cloud Gateway是Spring公司基于Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术

开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。它的目标是替代

Netflix Zuul,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安

全,监控和限流。

2.优缺点

优点

性能强劲:是第一代网关Zuul的1.6倍

功能强大:内置了很多实用的功能,例如转发、监控、限流等

设计优雅,容易扩展

缺点

其实现依赖Netty与WebFlux,不是传统的Servlet编程模型,学习成本高

不能将其部署在Tomcat、Jetty等Servlet容器里,只能打成jar包执行

需要Spring Boot 2.0及以上的版本,才支持

3.传统的过滤器

代码如下(示例):

@WebFilter(filterName="MyFliter",urlPatterns="/api/share/*")

public class MyFliter implements Filter {

@Override

public void init(FilterConfig filterConfig) throws ServletException {

System.out.println("");

}

@Override

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

System.out.println("filter 进入之前");

filterChain.doFilter(servletRequest,servletResponse);

System.out.println("filter 进入之后");

}

@Override

public void destroy() {

}

}

//在主程序处加上注解

//@ServletComponentScan("过滤器包名")

4.使用gateway

4.1module

4.2添加pom依赖

代码如下(示例):

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

springcloud_nacos

com.csdn

1.0-SNAPSHOT

4.0.0

springcloud_gateway

org.springframework.boot

spring-boot-starter-data-redis-reactive

org.springframework.cloud

spring-cloud-starter-gateway

com.alibaba.cloud

spring-cloud-starter-alibaba-nacos-discovery

com.csdn

springcloud_common

${project.version}

org.springframework.boot

spring-boot-starter-web

org.springframework.boot

spring-boot-maven-plugin

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

springcloud_nacos

com.csdn

1.0-SNAPSHOT

4.0.0

springcloud_gateway

org.springframework.boot

spring-boot-starter-data-redis-reactive

org.springframework.cloud

spring-cloud-starter-gateway

com.alibaba.cloud

spring-cloud-starter-alibaba-nacos-discovery

com.csdn

springcloud_common

${project.version}

org.springframework.boot

spring-boot-starter-web

org.springframework.boot

spring-boot-maven-plugin

4.3yaml配置

代码如下(示例):

server:

port: 7000

spring:

application:

name: api-gateway

cloud:

nacos:

discovery:

server-addr: localhost:8848 # 将gateway注册到nacos

gateway:

discovery:

locator:

enabled: true # 让gateway从nacos中获取服务信息

routes:

- id: share-6002 # 只要唯一标识就行

uri: lb://share-6002 #真是的地址

order: 1

predicates: # 满足断言中的条件才理由

- Path=/api/share/**,/admin/share/**

- id: user-6001 # 只要唯一标识就行

uri: lb://user-6001 #真是的地址

order: 1

predicates: # 满足断言中的条件才理由

- Path=/api/user/**,/admin/user/**

4.4主程序开启注解@EnableDiscoveryClient

@EnableDiscoveryClient和@EnableEurekaClient共同点就是:都是能够让注册中心能够发现,扫描到该服务。

@EnableEurekaClient只适用于Eureka作为注册;@EnableDiscoveryClient 可以是其他注册中心。

代码如下(示例):

@SpringBootApplication

@EnableDiscoveryClient

public class GatewayApplication {

public static void main(String[] args) {

SpringApplication.run(GatewayApplication.class,args);

}

}

四、执行流程

1:基本概念

路由(Route)是 gateway中最基本的组件之一,表示一个具体的路由信息载体。主要定义了下面几个信息:

-

-

id

路由标识符,区别于其他 Route

uri

路由指向的目的地uri,即客户端请求最终被转发到的微服务。

order

用于多个Route 之间的排序,数值越小排序越靠前,匹配优先级越高。

http://

predicate

断言的作用是进行条件判断,只有断言都返回真,才会真正的执行路由。

filter

过滤器用于修改请求和响应信息。

DispatcherHandler:所有请求的调度器,负载请求分发

RoutePredicateHandlerMapping:路由谓语匹配器,用于路由的查找,以及找到路由后返回对应的WebHandler,DispatcherHandler会依次遍历HandlerMapping集合进行处理

FilteringWebHandler:使用Filter链表处理请求的WebHandler ,

RoutePredicateHandlerMapping找到路由后返回对应的FilteringWebHandler对请求进行处理,FilteringWebHandler负责组装Filter链表并调用链表处理请求。

五、断言

Predicate(断言, 谓词) 用于进行条件判断,只有断言都返回真,才会真正的执行路由。

断言就是说: 在 什么条件下 才能进行路由转发

链接: https://jb51.net/article/219232.htm

5.1: 自定义断言

添加自定义断言类

package gateway.pradicate;

import com.alibaba.nacos.common.utils.StringUtils;

import lombok.Data;

import lombok.NoArgsConstructor;

import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;

import org.springframework.stereotype.Component;

import org.springframework.web.server.ServerWebExchange;

import java.util.Arrays;

import java.util.List;

import java.util.function.Predicate;

@Component

public class AgeRoutePredicateFactory extends AbstractRoutePredicateFactory {

// 1: 配置类,用于接收配置文件中的对应参数

@Data

@NoArgsConstructor

public static class Config {

private int minAge;//18 对应断言配置中的第一个参数

private int maxAge;//60 对应断言配置中的第二个参数

}

// 2: 构造函数

public AgeRoutePredicateFactory() {

super(Config.class);

}

//3: 读取配置文件的中参数值 给他赋值到配置类中的属性上

public List shortcutFieldOrder() {

//这个位置的顺序必须跟配置文件中的值的顺序对应

return Arrays.asList("minAge", "maxAge");

}

//4: 断言逻辑

public Predicate apply(Config config) {

return new Predicate() {

@Override

public boolean test(ServerWebExchange serverWebExchange) {

// 4.1 接收前台传入的age参数

String ageStr = serverWebExchange.getRequest().getQueryParams().getFirst("Age");

//4.2 先判断是否为空

if (StringUtils.isNotEmpty(ageStr)) {

//3 如果不为空,再进行路由逻辑判断

int age = Integer.parseInt(ageStr);

if (age < config.getMaxAge() && age > config.getMinAge()) {

return true;

} else {

return false;

}

}

return false;

}

};

}

}

在需要判断的的routes下配置

5.2: 过滤器

链接: https://cnblogs.com/fx-blog/p/11751977.html.

分类:局部过滤器(作用在某一个路由上)全局过滤器(作用全部路由上)Gateway的Filter从作用范围可分为两种: GatewayFilter与GlobalFilter。GatewayFilter:应用到单个路由或者一个分组的路由上。

GlobalFilter:应用到所有的路由上。

内置过滤器举例:

注意要从网关访问

自定义局部过滤器

添加自定义Log配置

@Component

@Slf4j

public class LogGatewayFilterFactory

extends AbstractGatewayFilterFactory {

//1: 配置类 接收配置参数

@Data

@NoArgsConstructor

public static class Config {

private boolean consoleLog;

}

//2: 构造函数【固定写法】

public LogGatewayFilterFactory() {

super(Config.class);

}

//3: 读取配置文件中的参数 赋值到 配置类中

@Override

public List shortcutFieldOrder() {

return Arrays.asList("consoleLog");

}

//4: 过滤器逻辑

@Override

public GatewayFilter apply(Config config) {

return new GatewayFilter() {

Long start = System.currentTimeMillis();

@Override

public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {

// 进入服务之前

if (config.isConsoleLog()) {

log.info("{} 进入 {}",new Date(), exchange.getRequest().getPath());

}

// 调用服务 并且定义服务回来之后的逻辑

// 注意 如果此时仅仅只是需要进入之前的验证 不需要服务执行完之后的逻辑 可以 return chain.filter(exchange)即可

return chain.filter(exchange).then(Mono.fromRunnable(()->{

if (config.isConsoleLog()) {

Long end = System.currentTimeMillis();

log.info("{} 退出 {}. 共耗时:{}",new Date(), exchange.getRequest().getPath(),(end-start));

}

}));

}

};

}

}

全局过滤器

全局过滤器作用于所有路由, 无需配置。通过全局过滤器可以实现对权限的统一校验,安全性验证等功

自定义全局过滤器

//自定义全局过滤器需要实现GlobalFilter和Ordered接口

@Component

public class MyGloablFilter implements GlobalFilter, Ordered {

// 过滤逻辑

@Override

public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {

// 1 进入之前 controller

System.out.println("进入之前 在 MyGloablFilter");

// 2 放行

return chain.filter(exchange).then(Mono.fromRunnable(() -> {

// 在回调中写 返回的逻辑 response

System.out.println("从controller 回来之后");

}));

//3 回调

}

// 返回的数字越小 就越先起作用

@Override

public int getOrder() {

return 0;

}

}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:使用Jackson反序列化遇到的问题及解决
下一篇:java基础的详细了解第六天
相关文章

 发表评论

暂时没有评论,来抢沙发吧~