SpringBoot之Zuul服务

概述

Spring Cloud Netflix zuul组件是微服务架构中的网关组件,Zuul作为统一网关,是所有访问该平台的请求入口,核心功能是路由和过滤

目前公司业务就是基于Zuul搭建的网关服务,且提供的服务包括转发请求(路由)、黑名单IP访问拦截、URL资源访问时的权限拦截、统一访问日志记录/异常处理/单点登录引导功能本文主要内容:Zuul的执行流程、Zuul过滤实现、Zuul安全配置、Zuul路由配置、Zuul集成Hystrix、Zuul集成Zipkin与Sleuth

Zuul项目实战

Zuul执行流程

  • 接收请求
    • 客户端发送请求到Zuul服务器(前置经过Nginx反向代理)
  • Pre-filters
    • 请求首先通过Pre类型的过滤器,这些过滤器可以进行安全检查、身份验证、日志记录、选择路由等操作。
  • 路由转发Routing
    • 如果Pre-filter通过请求将被路由到具体的微服务实例上。Zuul 可以根据配置的路由规则将请求转发到不同的后端服务。
  • 服务调用
    • Zuul通过Fegin进行客户端负载均衡,选择一个服务实例进行调用
  • Post-filters
    • 服务处理完成后,响应会返回并经过 Post 类型的过滤器,这些过滤器可以修改返回的响应头、收集统计信息等。最终Zuul将响应发送回客户端
  • Error-filters
    • 如果在任何阶段发生错误,请求将被转发到 Error 类型的过滤器,进行错误处理后经过Post-filters,最终Zuul将响应发送回客户端

Zuul过滤器

网关过滤器
pre-filter

前置过滤器在请求被路由到源服务器之前执行,通常继承ZuulFilter抽象类。实际项目中我们使用前置过滤器对于400到500的状态错误码进行过滤,进而对于从cas认证服务中获取token的特定请求进行错误日志的记录

package test.gateway.filter;

import org.springframework.cloud.netflix.zuul.util.ZuulRuntimeException;
import test.common.util.R;
import com.google.gson.Gson;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;

/**
 * @Description: 捕获400到500错误码,否则不执行该过滤器
 */
public class ErrorStatusCodeZuulFilter extends ZuulFilter {
	
	protected static String GET_TOKEN_URI =  "/cas/getToken";
	
    @Override
    public String filterType() {
        return "post";
    }

    @Override
    public int filterOrder() {
        return -1; // Needs to run before SendResponseFilter which has filterOrder == 0
    }

    @Override
    public boolean shouldFilter() {    		
    		int statusCode = Integer.parseInt(RequestContext.getCurrentContext().get("responseStatusCode").toString());
    		return statusCode >= 400 && statusCode <= 500;
    }

	@Override
	public Object run() {
		RequestContext ctx = RequestContext.getCurrentContext();
		int statusCode = Integer.parseInt( ctx.get("responseStatusCode").toString());	
		String uri = ctx.get("requestURI").toString();
		if (uri != null && uri.equals(GET_TOKEN_URI)) { //获取token请求失败
			R<String>  res = new R<>();		
			res.setCode(statusCode);
			res.setData(null);
			res.setMsg("Account or password error");
			ctx.setResponseBody(new Gson().toJson(res));
			return null;
		}
		try {
			throw new Exception();
		} catch (Throwable t) {	    		
			throw new ZuulRuntimeException(new ZuulException(t, statusCode, t.getMessage()));
		}
	}
}
routing-filter

处理将请求发送到源服务器的逻辑

post-filter

后置过滤器在请求被路由后执行,可以对响应进行修改或添加额外的HTTP等。

error-filter

当请求处理过程中发生错误时,这些过滤器会被调用,同时最终也会调用后置post类型过滤器返回 

扩展-OncePerRequestFilter

OncePerRequestFilter是Spring Framework中的一个接口,它属于Servlet过滤器(Filter)的范畴,但不是Zuul中定义的特定过滤器类型。在Spring MVC中,OncePerRequestFilter确保每个请求只被处理一次。它通过同步代码块来保证,即使在支持异步处理的 Spring MVC 应用程序中,请求也不会被重复处理。项目中我们通过自定义过滤器(继承OncePerRequestFilter)处理访问公共接口且未携带token的请求,该过滤器也属于前置的过滤器,因为它通常用于在请求进入其他阶段之前执行某些操作。

Zuul安全配置

自定义WebSecurityConfig

在Spring Security的上下文中,WebSecurityConfig类通常用于配置Spring Security的安全策略。此类继承自WebSecurityConfigurerAdapter,WebSecurityConfig可以用来定义Zuul网关的安全设置,通过提供了一种自定义安全配置的方法实现,实际项目中我们对zuul进行的http请求相关安全配置

package test.zuul.config;
import ...

/**
 * @Description: Zuul http configuration
 */
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { // 定义Zuul网关的安全设置
	private final static Logger logger = LoggerFactory.getLogger(WebSecurityConfig.class);
	
	@Autowired
    private FilterIgnorePropertiesConfig filterIgnorePropertiesConfig;
	
	@Autowired
	private FindByIndexNameSessionRepository<? extends Session> sessionRepository;
	
	@Autowired
	private RedisOperationsSessionRepository redisOperationsSessionRepository; 
	
	@Autowired
	private AuthenticationServiceFeign authenticationService;
	
    @Override
    public void configure(HttpSecurity http) throws Exception {
    		http
    			.csrf()
    			.disable(); //禁用csrf
    		http
    			.headers()
    			.frameOptions()
    			.disable();
    		ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry =
	    	http
	    		.antMatcher("/**") // 允许所有请求
		        .authorizeRequests();
			filterIgnorePropertiesConfig.getUrls().forEach(url -> registry.antMatchers(url).permitAll());
			registry
		    	.anyRequest()
		        .authenticated();
		    http
		        .exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login/idpbg"))	        
		        .and()
		        .logout().logoutUrl("/logout").addLogoutHandler(new LogoutHandler() { //登出后处理逻辑
					@Override
					public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {					
						if(authentication != null) {
							String indexName = authentication.getName();
							// 查询用户的 Session 信息      
							Map<String, ? extends Session> userSessions = sessionRepository.findByIndexNameAndIndexValue(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, indexName);
							
							// 删除当前用户相关session
							List<String> sessionIds = new ArrayList<>(userSessions.keySet());
							for (String session : sessionIds) {
								redisOperationsSessionRepository.deleteById(session);
							}
							//删除系统当前在线用户信息...
						}
						Cookie cookie = new Cookie();
						//重置cookie...
						response.addCookie(cookie);
					}
				}).logoutSuccessHandler(logoutSuccessHandler()).oauth2Login().and().oauth2Client();	
    }
    
    private LogoutSuccessHandler logoutSuccessHandler() { //登出成功后处理逻辑
		return new LogoutSuccessHandler() {
			@Override
			public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
					throws IOException, ServletException {
				if(authentication != null) {
					if(authentication.getDetails() instanceof OAuth2AuthenticationDetails) {
						// 刪除JWT
						......
					}
				}
				new SecurityContextLogoutHandler().logout(request, null, null);
				try {
					response.sendRedirect("/"); //重定向到登录页面
					}
		        } catch (IOException e) {
		            e.printStackTrace();
		        }
			}
		};
	}
}

Zuul-路由规则

  # 默认情况下所有的eureka上的服务都会被zuul自动地创建映射关系来进行路由,
  # 设置ignored-services: '*' 时,避免注册到Eureka中的服务被Zuul默认路由,从而避免不必要的服务暴露
  ignored-services: '*' 

  routes:
    # CAS 路由配置
    cas-server:
      sensitiveHeaders: 
      path: /cas/**
      serviceId: cas-server
      strip-prefix: false #表示Zuul不会移除请求的URI路径前面的/cas/部分
    # END CAS路由配置

	..其他服务路由配置..

Zuul-熔断

在项目开发Zuul服务时,通常会集成Hystrix,并通过HystrixH对依赖的微服务进行熔断保护,防止单个服务的故障影响到整个系统

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            # hystrix超时时间计算方法 = ribbonTimeout(ReadTimeout + ConnectTimeout) * (maxAutoRetries + 1) * (maxAutoRetriesNextServer + 1)
			#  timeoutInMilliseconds = (600000 + 600000) * 1 * 2
            timeoutInMilliseconds: 2400000
  # 仅正式局配置Threadpool参数
  threadpool:
    default:
      coreSize: 50
      maximumSize: 10000
      allowMaximumSizeToDivergeFromCoreSize: true
      maxQueueSize: -1

ribbon:  
  # Zuul 如果使用 Eureka查找路由,则需要配置ConnectTimeout和SocketTimeout
  ConnectTimeout: 600000 # 6min,由于通过网关存在下载/导报表服务,此类需求建立连接耗时比较长,所以设置为6min
  SocketTimeout: 600000 # 6min,由于通过网关存在下载/导报表服务,此类需求建立连接耗时比较长,所以设置为6min
  ReadTimeout: 600000  # 6min,由于通过网关存在下载/导报表服务,此类需求建立连接耗时比较长,所以设置为6min
  MaxAutoRetries: 0
  MaxAutoRetriesNextServer: 1 #下一个服务调用自动重试次数
  MaxTotalConnections: 400  # okhttp模式下最大连接数量
  eureka:
    enabled: true #通过Eureka路由到具体微服务
  httpclient:
    enabled: false
  okhttp:  #use okhttp will better
    enabled: true
    
feign: 
  httpclinet: #use okhttp will better
    enabled: false
  okhttp: 
    enabled: true 

Zuul-Zipkin与Sleuth

Sleuth是Spring Cloud的一个组件,用于在微服务架构中提供分布式跟踪解决方案。Sleuth通常与Zipkin等分布式跟踪系统配合使用,可以生成请求链路的跟踪信息,帮助开发者理解请求在系统中流动的路径,从而优化性能和定位问题,项目中我们在application.yml文件配置:

 zipkin:
    #base-url: http://10.169.33.369/  # Zipkin Server URL, 仅当spring.zipkin.sender.type=web才需要设置,基于消息服务则不需要设置
    enabled: true # 启用Zipkin,默认true
    sender:
      type: rabbit  #  微服務基于消息服务发送 Zipkin Data到Zipkin Server
    rabbitmq:
      queue: zipkin  # 对应RabbitMq的队列名,仅当spring.zipkin.sender.type=rabbit时有效,默认配置为zipkin
  sleuth:
    web:
      client:
        enabled: true  # 对于web请求,是否开启sleuth功能。默认为true。
    sampler:
      probability: 0.1 # 1.0即100%收集 默认0.1

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/607716.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

在windows下使用VS Code、CMake、Make进行代码编译

软件环境 Windows11VS CodeNoneCMake3.26.4-windows-x86_64MinGWNone 电脑系统配置 安装MinGW将MinGW安装文件夹中bin文件夹下的mingw32-make.exe复制并重命名为make.exe在文件夹中添加系统路径&#xff0c;具体位置为 系统->系统信息->高级系统设置->高级->环境…

马化腾用“不负众望”,来评价视为“全村希望”的视频号

我是王路飞。 2023年的视频号&#xff0c;给了腾讯足够的惊喜。 去年一年&#xff0c;视频号电商GMV实现近3倍增长&#xff08;约为1200亿&#xff5e;1500亿&#xff09;。2023年三季度&#xff0c;视频号总播放量同比增长超50%&#xff1b; 2023年视频号供给数量同比增长超…

【python】模拟巴特沃斯滤波器

巴特沃斯滤波器&#xff08;Butterworth Filter&#xff09;&#xff0c;以其设计者斯蒂芬巴特沃斯&#xff08;Stephen Butterworth&#xff09;的名字命名&#xff0c;是一种具有平滑频率响应的滤波器。这种滤波器在频域中具有非常平坦的无波纹响应&#xff0c;直到它达到截止…

一文了解CloudXR优势及应用原理

CloudXR是一种新颖而先进的技术&#xff0c;旨在将虚拟现实和增强现实体验从本地设备转移到云端&#xff0c;主要功能也包括了远程渲染、流媒体传输、低延迟、高带宽和高质量的音视频传输。CloudXR&#xff08;云化XR&#xff09;可以将高保真度的虚拟现实或增强现实场景实时传…

线程的常见方法

线程的常见方法 休眠&#xff1a; 让当前状态不再参与cpu的竞争&#xff0c;直到休眠结束&#xff1b; 结果&#xff1a;并不是完全交替进行的&#xff0c;因为只是休眠状态&#xff0c;也会存在争抢cpu 放弃&#xff1a; 让当前状态主动放弃时间片&#xff0c;下次再去争抢…

如何在PPT中插入网页?这样操作,免费还高效!

融合课、跨学科课&#xff0c;已经是近两年来教育界的热门词。 在公开课、微课比赛中&#xff0c;不添融合一些较为先进的信息技术&#xff0c;都不好意思拿出手了。 最近&#xff0c;由不坑老师开发制作的Office插件——不坑盒子&#xff0c;实现了在PPT中插入网页&#xff…

[性能优化] ScrollView视图优化为循环列表

问题描述&#xff1a; 原先商城的物品栏中的item 是load在一个scrollView 下&#xff0c;用于滑动查看。仅仅在父级panel下是使用了NGUI原生的scrollview 组件&#xff0c;随着商场物品列表中新物品的增多。panel下加载的实例也非常庞大。而大部分的实例用户也无法看到&#x…

es使用遇到的bug总结

本来版本7.4.0不行&#xff0c;最后换了个版本7.15.1就可以了&#xff0c;但又出现以下问题了&#xff1a; Beanpublic ElasticsearchClient elasticsearchClient() { // RestClient client RestClient.builder(new HttpHost("localhost", 9200,"http&q…

Duplicate entry ‘asdfg‘ for key ‘clazz.name‘

Mybatis:java.sql.SQLIntegrityConstraintViolationException:Duplicate entry ‘asdfg’ for key ‘clazz.name’ 违反了数据库的唯一约束条件&#xff0c;即插入数据的时候具有唯一约束&#xff08;被unique修饰&#xff09;的列值重复了 在修改的过程中发生错误&#xff0c;…

一文玩转Vue3参数传递——全栈开发之路--前端篇(8)

全栈开发一条龙——前端篇 第一篇&#xff1a;框架确定、ide设置与项目创建 第二篇&#xff1a;介绍项目文件意义、组件结构与导入以及setup的引入。 第三篇&#xff1a;setup语法&#xff0c;设置响应式数据。 第四篇&#xff1a;数据绑定、计算属性和watch监视 第五篇 : 组件…

ORA-02020:过多的数据库链接在使用

一、问题描述 今天同事说&#xff0c;有一个查询功能&#xff0c;同时查了几个子平台的dblink&#xff0c;页面返回报错。 提示ORA-02020&#xff1a;过多的数据库链接在使用&#xff1b; bad SQL grammar 二、解决办法 1&#xff09;分析业务需求 分析业务场景 &#xff0c;发…

基于Vue3与ElementUI Plus的酷企秀场景可视化DIY设计器:前端技术引领下的数字化展示新篇章

一、引言 在当今信息化高速发展的时代&#xff0c;企业对于展示自身形象、提升用户体验以及增强品牌知名度的需求日益迫切。针对这一市场需求&#xff0c;我们推出了基于Vue3与ElementUI Plus的酷企秀场景可视化DIY设计器。该产品不仅具备电子画册、VR全景、地图秀三大核心功能…

Mybatis存储数据将数据转为json

第一种方法 先创建一个表类型如下 创建一个项目&#xff0c;写一个接口 &#xff0c; 写一个JsonTypeHandler类继承BaseTypeHandler public class JsonTypeHandler<T> extends BaseTypeHandler<T> {private Class<T> clazz;//构造函数 --- >接收一个 Cl…

大数据Scala教程从入门到精通第五篇:Scala环境搭建

一&#xff1a;安装步骤 1&#xff1a;scala安装 1&#xff1a;首先确保 JDK1.8 安装成功: 2&#xff1a;下载对应的 Scala 安装文件 scala-2.12.11.zip 3&#xff1a;解压 scala-2.12.11.zip 4&#xff1a;配置 Scala 的环境变量 在Windows上安装Scala_windows安装scala…

多线程三种实现

多线程 线程 线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中&#xff0c;是进程中的实际运作单位。 &#xff08;理解&#xff1a;应用软件中互相独立&#xff0c;可以同时运行的功能&#xff09; 进程 进程是程序的基本执行实体。&#xff08;理解&#…

【动态规划】:路径问题_地下城游戏

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本专栏是关于各种算法的解析&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数据结构专栏&…

【LLM 论文】Least-to-Most Prompting 让 LLM 实现复杂推理

论文&#xff1a;Least-to-Most Prompting Enables Complex Reasoning in Large Language Models ⭐⭐⭐ Google Research, ICLR 2023 论文速读 Chain-of-Thought&#xff08;CoT&#xff09; prompting 的方法通过结合 few-show prompt 的思路&#xff0c;让 LLM 能够挑战更具…

MySQL#MySql表的操作

目录 一、创建表 二、查看表结构 三、修改表 1.修改表的名字 2.新增一个列 3.修改列 4.删除列 5.修改列的名称 四、删除表 一、创建表 语法&#xff1a; CREATE TABLE table_name (field1 datatype,field2 datatype,field3 datatype ) character set 字符集 collate 校…

2042193-77-9,BDP FL甲基四嗪可用于标记细胞和组织样本

1.基本信息&#xff1a; BDP FL甲基四嗪是一种具有独特化学和光学性质的化合物。 2.化学结构&#xff1a; BDP FL甲基四嗪是含有甲基四嗪基团的BDP染料连接体。BDP FL部分是指附着在甲基四嗪上的荧光标记&#xff0c;使其在暴露于特定波长的光时能够发光。 甲基四嗪是一种具有…

C语言【文件操作 2】

文章目录 前言顺序读写函数的介绍fputc && fgetcfputcfgetc fputs && fgetsfputsfgets fprintf && fscanffprintffscanf fwrite && freadfwritefread 文件的随机读写fseek函数偏移量ftell函数rewind函数 文件的结束判断被错误使用的feof 结语 …