网关的理解
网关类似于
海关或者大门,出入都需要经过这个网关。别人不经过这个网关,永远也看不到里面的东西。可以在网关进行条件过滤,比如大门只有对应的钥匙才能入内。网关和大门一样,永远暴露在最外面
不使用网关
前端需要记住每一个服务的IP和port
如果有一个服务部署多台,那么前端需要自行分配
使用网关
前端不需要记每一个服务的IP和port,只需要将请求发送到网关即可,网关根据资源路径做
路由跳转网关中可以做
安全控制比如Token校验、限流等可以做
负载均衡
Gateway的理解
是Spring官网推出的一套网关组件,用来取代Zuul
它的目的是为了让
路由跳转更加方便、灵活,还提供了一些强大的过滤器功能。比如:IP黑名单、Token校验等
基于webFlux框架实现,webFlux框架底层使用了高性能的Reactor模式通信框架的Netty
Gateway是在Spring生态系统之上构建的API网关服务,基于Spring 5,Spring Boot 2和Project Reactor等技术。
Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能,例如:熔断、限流、重试等。
① Gateway工作原理
客户端发送请求到Gatewaty,然后Gateway HandlerMapping通过对比映射,找到与其匹配的路由,将其发送到Gateway WebHandler。Handler再通过指定的过滤器将请求分发到实际的业务逻辑,并返回。
在过滤器中可以做增加代码:
在
请求之前[pre]做校验等在
请求之后[post]做日志输出等Gateway核心逻辑:根据资源路径做路由转发,并且执行过滤器链。
② Gateway三大核心概念
路由(Route)
和eureka结合做动态路由
组成部分:一个路由ID、一个唯一资源定位符URI、一组断言、一组Filter
如果路由断言为真,那么URL和配置路由匹配
断言(Predicate)
返回一个boolean表达式
过滤器(Filter)
Gateway中的过滤器分为Gateway Filter(针对一个路由)和Global Filter(全局)
在过滤器中可以编写校验规则以及响应的处理
③ Gateway和Nginx区别
Nginx做限流、负载均衡、路由都需要修改nginx.conf配置文件
Gateway和eureka结合,实现了自动路由跳转;和Ribbon集合,实现了负载均衡。Gateway也能够通过配置进行限流的实现
![]()
路由使用
① 访问流程
② Loing-service
@RestController public class LoginController { @GetMapping("doLogin") public String doLogin(String username,String password){ System.out.println(username+" -> "+password); String token = UUID.randomUUID().toString(); return token; } }② Gateway-server
gateway依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>配置路由
server: port: 80 spring: application: name: gateway-server cloud: gateway: enabled: true # 默认开启Gateway routes: # 路由组 - id: login-service-route # 路由ID 保证唯一 uri: http://localhost:8080 # uri唯一资源定位符 url唯一资源标识符 predicates: # 断言 - Path=/doLogin # 和服务中的路径匹配④ 编程式路由
不借助配置文件,使用编码的方式来实现路由转发
@Configuration public class RouteConfig { @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { return builder.routes() .route("anime-id", r->r.path("/anime").uri("https://www.bilibili.com")) .route("variety-id",r->r.path("/variety").uri("https://www.bilibili.com")) .build(); } }如果在
uri后面的资源路径和path中的路由一样,那么gateway不会把path中的路由拼接到uri后面。编程式和配置文件的方式可以结合使用
动态路由
如果在路由转发时直接将URL写死,从而IP和port也被写死,那么Gateway将无法达到负载均衡的效果。应该是只提供服务名,然后通过这个名字去找对应的服务,从而达到负载均衡的效果
让Gateway服务也注册到注册中心中,那么Gateway就能够拥有所有的服务信息
Gateway会根据注册中心中的服务列表,以每个
服务名为路径创建动态路由进行转发① 第一种实现方式
使用lb(Load Balance)协议,表示启用Gateway的负载均衡功能
server: port: 80 spring: application: name: gateway-server cloud: gateway: enabled: true # 默认开启Gateway routes: # 路由组 - id: login-service-route # 路由ID 保证唯一 # uri: http://localhost:8080 # uri唯一资源定位符 url唯一资源标识符 uri: lb://login-service # lb://服务名 predicates: - Path=/doLogin # 和服务中的路径匹配② 第二种实现方式
使用服务发现,自动创建动态路由从而实现负载均衡
server: port: 80 spring: application: name: gateway-server cloud: gateway: enabled: true # 默认开启Gateway discovery: locator: enabled: true # 开启动态路由 lower-case-service-id: true # 将注册列表中的服务名小写
断言
在项目启动的时候,Gateway会去加载一些路由断言工厂,例如:After、Query
断言就是给路由增加一些
匹配规则,如果发送的请求符合这些规则,就能够去访问,否则404。简单说这些匹配规则也就是一些boolean表达式,要么true进入,要么false拒绝① 分类
![]()
② 使用
在配置文件中,对某个路由进行操作。动态路由不能使用断言
spring: application: name: gateway-server cloud: gateway: enabled: true # 默认开启Gateway routes: - id: login-service-route uri: lb://login-service predicates: - Path=/doLogin - Method=GET,POST # GET,POST请求能够访问 - After=2022-11-02T17:23:16.423+08:00[Asia/Shanghai] # 在指定时间后才能访问 通过ZonedDateTime获取 - Query=username,admin. # 必须给username传值 后面的值必须是:adminx
过滤器
Gateway中的过滤器和Servlet里面的过滤器差不多,用户修改进入HTTP请求和HTTP响应
分为GatewayFilter(针对某一个路由)和GlobalFilter(全局过滤)
① 自定义全局过滤器
在自定义过滤器中编写业务逻辑,比如Token校验、限流。
@Component public class TestFilter implements GlobalFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 获取请求对象 ServerHttpRequest request = exchange.getRequest(); RequestPath path = request.getPath(); // 打印路由以及服务名 System.out.println(path); HttpHeaders headers = request.getHeaders(); // 获取主机IP String ip = headers.getHost().getHostName(); System.out.println(ip); // 获取响应对象 ServerHttpResponse response = exchange.getResponse(); // 放过 return chain.filter(exchange); } }定义过滤器顺序
@Component public class TestFilter implements Ordered { @Override public int getOrder() { // 数字越小 越往前 return 0; } }返回值处理
// 获取响应对象 ServerHttpResponse response = exchange.getResponse(); // 设置响应头 response.getHeaders().set("content-Type","application/json;charset=UTF-8"); // 封装返回数据 Map<String,Object> map = new HashMap<>(); map.put("code", 401); map.put("msg","没有该权限"); ObjectMapper objectMapper = new ObjectMapper(); try { // 将map集合转为byte数组 byte[] bytes = objectMapper.writeValueAsBytes(map); // 将byte数组包装成一个数据缓冲包 DataBuffer wrap = response.bufferFactory().wrap(bytes); // 返回 return response.writeWith(Mono.just(wrap)); } catch (JsonProcessingException e) { e.printStackTrace(); }
限流
在一定的时间段内,限制用户的访问频率。
① 限流模型
漏斗算法、令牌通算法、计算器算法、窗口滑动算法
入不敷出:生产令牌的速度赶不上使用的速度
系统以提前配置好的速率去生产令牌。
给令牌桶设置一个阈值,当桶满后,多余的令牌直接丢弃
客户发送请求都需要去拿令牌
如果没有拿到令牌该请求不能成功访问
如果拿到令牌将去访问服务,完成业务处理后删除令牌
当桶中的令牌数达到最低额度时,使用完的令牌返回
② Gateway中的限流
Gateway中已经内置了RequestRateLimiterGatewayFilterFactory,结合Redis做令牌桶算法。需要导入redis依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis-reactive</artifactId> </dependency>配置限流规则
@Configuration public class RequestLimiterConfig { /* 基于IP做限流 */ @Bean @Primary // 主候选 public KeyResolver ipKeyResolver(){ return exchange-> Mono.just(exchange.getRequest().getHeaders().getHost().getHostName()); } /* 基于API接口最限流 */ @Bean public KeyResolver apiKeyResolver(){ return exchange -> Mono.just(exchange.getRequest().getPath().toString()); } }修改配置文件
spring: application: name: gateway-server cloud: gateway: enabled: true # 默认开启Gateway routes: - id: login-service-route uri: lb://login-service predicates: - Path=/doLogin filters: - name: RequestRateLimiter # 过滤器名称 args: key-resolver: '#{@ipKeyResolver}' # Bean对象的名字 redis-rate-limiter.replenishRate: 1 # 每秒钟生产多少令牌 redis-rate-limiter.burstCapacity: 3 # 令牌桶中的容量只针对某一个路由
跨域配置
跨域:
CORS同源策略。因为网关是服务的最边缘,所有的请求都需要走网关,将跨域的配置写在网关。
编程式
@Configuration public class CorsConfig { @Bean public CorsWebFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.addAllowedMethod("*"); config.addAllowedOrigin("*"); config.addAllowedHeader("*"); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser()); source.registerCorsConfiguration("/**", config); return new CorsWebFilter(source); } }配置文件
spring: cloud: gateway: globalcors: cors-configurations: '[/**]': # 针对那些路径 allowCredentials: true # 可以携带Cookie allowedHeaders: '*' allowedMethods: '*' allowedOrigins: '*'
面试题相关
什么是微服务网关
Spring Cloud Gateway 是 Spring 官方基于 Spring 5.x,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,Spring Cloud Gateway 旨在为微服务架构提供一种简单而有效的统一的 API 路由管理方式。Spring Cloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Netflix Zuul,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全性、监视/指标和弹性。
使用Gateway的优势
Spring Cloud Gateway 可以看做是一个 Zuul 1.x 的升级版和代替品,比 Zuul 2 更早的使用 Netty 实现异步 IO,从而实现了一个简单、比 Zuul 1.x 更高效的、与 Spring Cloud 紧密配合的 API 网关。
Spring Cloud Gateway 里明确的区分了 Router 和 Filter,并且一个很大的特点是内置了非常多的开箱即用功能,并且都可以通过 SpringBoot 配置或者手工编码链式调用来使用。
比如内置了 10 种 Router,使得我们可以直接配置一下就可以随心所欲的根据 Header、或者 Path、或者 Host、或者 Query 来做路由。
比如区分了一般的 Filter 和全局 Filter,内置了 20 种 Filter 和 9 种全局 Filter,也都可以直接用。当然自定义 Filter 也非常方便。zuul和spring cloud gateway的对比
- zuul:是Netflix的,是基于servlet实现的,阻塞式的api,不支持长连接。
- gateway:是springcloud自己研制的微服务网关,是基于Spring5构建,能够实现响应式非阻塞式的Api,支持长连接
gateway的组成
- 路由 : 网关的基本模块,有ID,目标URI,一组断言和一组过滤器组成
- 断言:就是访问该旅游的访问规则,可以用来匹配来自http请求的任何内容,例如headers或者参数
- 过滤器:这个就是我们平时说的过滤器,用来过滤一些请求的,gateway有自己默认的过滤器,具体请参考官网,我们也可以自定义过滤器,但是要实现两个接口,ordered和globalfilter
Region是HBase数据管理的基本单位,region有一点像关系型数据的分区。region中存储这用户的真实数据,而为了管理这些数据,HBase使用了RegionSever来管理region。Region的结构hbaseregion的大小设置默认情况下,每个Table起初只有一个Region,随着数据的不断写入,Region会自动进行拆分。刚拆分时,两个子Region都位于当前的RegionServer,但处于负载均衡的考虑,HMaster有可能会将某个Region转移给其他的RegionServer。RegionSplit时机:当1个region中的某个Store下所有StoreFile
目录SpringBootStarter是什么?以前传统的做法使用SpringBootStarter之后starter的理念:starter的实现: 创建SpringBootStarter步骤在idea新建一个starter项目、直接执行下一步即可生成项目。 在xml中加入如下配置文件:创建proterties类来保存配置信息创建业务类:创建AutoConfiguration测试如下:SpringBootStarter是什么? SpringBootStarter是在SpringBoot组件中被提出来的一种概念、简化了很多烦琐的配置、通过引入各种SpringBootStarter包可以快速搭建出一
昨晚看到IDEA官推宣布IntelliJIDEA2023.1正式发布了。简单看了一下,发现这次的新版本包含了许多改进,进一步优化了用户体验,提高了便捷性。至于是否升级最新版本完全是个人意愿,如果觉得新版本没有让自己感兴趣的改进,完全就不用升级,影响不大。软件的版本迭代非常正常,正确看待即可,不持续改进就会慢慢被淘汰!根据官方介绍:IntelliJIDEA2023.1针对新的用户界面进行了大量重构,这些改进都是基于收到的宝贵反馈而实现的。官方还实施了性能增强措施,使得Maven导入更快,并且在打开项目时IDE功能更早地可用。由于后台提交检查,新版本提供了简化的提交流程。IntelliJIDEA
介绍pytest是一个非常成熟的全功能的Python测试框架,主要有以下几个特点:简单灵活,容易上手支持参数化能够支持简单的单元测试和复杂的功能测试,还可以用来做selenium/appnium等自动化测试、接口自动化测试(pytest+requests)pytest具有很多第三方插件,并且可以自定义扩展,比较好用的如pytest-selenium(集成selenium)、pytest-html(完美html测试报告生成)、pytest-rerunfailures(失败case重复执行)、pytest-xdist(多CPU分发)等测试用例的skip和xfail处理可以很好的和jenkins集成
运行有问题或需要源码请点赞关注收藏后评论区留言一、利用ContentResolver读写联系人在实际开发中,普通App很少会开放数据接口给其他应用访问。内容组件能够派上用场的情况往往是App想要访问系统应用的通讯数据,比如查看联系人,短信,通话记录等等,以及对这些通讯数据及逆行增删改查。首先要给AndroidMaifest.xml中添加响应的权限配置 下面是往手机通讯录添加联系人信息的例子效果如下分成三个步骤先查出联系人的基本信息,然后查询联系人号码,再查询联系人邮箱代码 ContactAddActivity类packagecom.example.chapter07;importandroid
为什么需要服务网关传统的单体架构中只需要开放一个服务给客户端调用,但是微服务架构中是将一个系统拆分成多个微服务,如果没有网关,客户端只能在本地记录每个微服务的调用地址,当需要调用的微服务数量很多时,它需要了解每个服务的接口,这个工作量很大。有了网关之后,网关作为系统的唯一流量入口,封装内部系统的架构,所有请求都先经过网关,由网关将请求路由到合适的微服务。使用网关的好处1)简化客户端的工作。网关将微服务封装起来后,客户端只需同网关交互,而不必调用各个不同服务;(2)降低函数间的耦合度。一旦服务接口修改,只需修改网关的路由策略,不必修改每个调用该函数的客户端,从而减少了程序间的耦合性(3)解放开发
📝学技术、更要掌握学习的方法,一起学习,让进步发生👩🏻作者:一只IT攻城狮。💐学习建议:1、养成习惯,学习java的任何一个技术,都可以先去官网先看看,更准确、更专业。💐学习建议:2、然后记住每个技术最关键的特性(通常一句话或者几个字),从主线入手,由浅入深学习。❤️《SpringCloud入门实战系列》解锁SpringCloud主流组件入门应用及关键特性。带你了解SpringCloud主流组件,是如何一战解决微服务诸多难题的。项目demo:源码地址👉🏻SpringCloud入门实战系列不迷路👈🏻:SpringCloud入门实战(一)什么是SpringCloud?SpringCloud入门实战
我需要部署我的Rails应用程序,所以我从这里开始执行了所有步骤,https://www.digitalocean.com/community/tutorials/how-to-deploy-a-rails-app-with-puma-and-nginx-on-ubuntu-14-04但是在教程结束时,我得到了这个错误-->“502BadGateway”编辑现在的错误消息-->“很抱歉,出了点问题。”但是Nginx错误输出是相同的,我检查了puma错误消息,但它们只是记录它何时启动以及何时正常停止。位于app_directory/log下的Rails日志不产生任何输出。puma-man
我正在开发一个包含大约10个不同功能组件的Sinatra应用程序。我们希望能够将这些组件混合并匹配到应用程序的单独实例中,完全从config.yaml文件配置,如下所示:components:-route:'/chunky'component_type:FoodListercomponent_settings:food_type:baconmax_items:400-route:'places/paris'component_type:Mappercomponent_settings:latitude:48.85387273165654longitude:2.340087890625-
我正在为需要有条件地设置cookie的Rails应用编写Rack中间件组件。我目前正在尝试设置cookie。通过谷歌搜索,这似乎应该可行:classRackAppdefinitialize(app)@app=appenddefcall(env)@status,@headers,@response=@app.call(env)@response.set_cookie("foo",{:value=>"bar",:path=>"/",:expires=>Time.now+24*60*60})[@status,@headers,@response]endend它不会给出错误,但也不会设置coo