技术标签: Java Nginx spring cloud 注册中心 gateway Spring Cloud
Spring Cloud GateWay是Spring Cloud的⼀个全新项⽬,⽬标是取代Netflix Zuul,它基于Spring5.0+SpringBoot2.0+WebFlux(基于⾼性能的Reactor模式响应式通信框架Netty,异步⾮阻塞模型)等技术开发,性能⾼于Zuul,官⽅测试,GateWay是Zuul的1.6倍,旨在为微服务架构提供⼀种简单有效的统⼀的API路由管理⽅式。
Spring Cloud GateWay不仅提供统⼀的路由⽅式(反向代理)并且基于 Filter(定义过滤器对请求过滤,完成⼀些功能) 链的⽅式提供了⽹关基本的功能,例如:鉴权、流量控制、熔断、路径重写、⽇志监控等。
网关在架构中的位置,可以看到是请求进来由网关路由分配找到需要请求的服务,其中Nginx是用来做网关高可用的。
Spring Cloud GateWay天⽣就是异步⾮阻塞的,基于Reactor模型;
⼀个请求—>⽹关根据⼀定的条件匹配—匹配成功之后可以将请求转发到指定的服务地址;⽽在这个过程中,我们可以进⾏⼀些⽐较具体的控制(限流、⽇志、⿊⽩名单)
路由(route): ⽹关最基础的部分,也是⽹关⽐较基础的⼯作单元。路由由⼀个ID、⼀个⽬标URL(最终路由到的地址)、⼀系列的断⾔(匹配条件判断)和Filter过滤器(精细化控制)组成。如果断⾔为true,则匹配该路由。
断⾔(predicates):参考了Java8中的断⾔java.util.function.Predicate,开发⼈员可以匹配Http请求中的所有内容(包括请求头、请求参数等)(类似于nginx中的location匹配⼀样),如果断⾔与请求相匹配则路由。
过滤器(filter):⼀个标准的Spring webFilter,使⽤过滤器,可以在请求之前
或者之后执⾏业务逻辑。
Predicates断⾔就是我们的匹配条件,⽽Filter就可以理解为⼀个⽆所不能的拦截器,有了这两个元素,结合⽬标URL,就可以实现⼀个具体的路由转发。
Spring Cloud GateWay 帮我们内置了很多 Predicates功能,实现了各种路由匹配规则(通过 Header、请求参数等作为条件)匹配到对应的路由。
一般都会使用请求路径正则匹配
spring:
cloud:
gateway:
routes: # 路由可以有多个
- id: service-xxx-router # 我们⾃定义的路由 ID,保持唯⼀
uri: lb://server-name
predicates: #路由条件
- Path=/xx/xxxx/**
客户端向Spring Cloud GateWay发出请求,然后在GateWay Handler Mapping中找到与请求相匹配的路由,将其发送到GateWay Web Handler;Handler再通过指定的过滤器链来将请求发送到我们实际的服务执⾏业务逻辑,然后返回。过滤器之间⽤虚线分开是因为过滤器可能会在发送代理请求之前(pre)或者之后(post)执⾏业务逻辑。
Filter在“pre”类型过滤器中可以做参数校验、权限校验、流量监控、⽇志输出、协议转换等,在“post”类型的过滤器中可以做响应内容、响应头的修改、⽇志的输出、流量监控等。
从过滤器⽣命周期(影响时机点)的⻆度来说,主要有两个pre和post:
从过滤器类型的⻆度 ,Spring Cloud GateWay的过滤器分为GateWayFilter和GlobalFilter两种。
一般情况下GlobalFilter全局过滤器是程序员使⽤⽐较多的过滤器;
可以用来自定义一些黑名单校验等
⾃定义GateWay全局过滤器时,我们实现Global Filter接⼝即可,通过全局过滤器可以实现⿊⽩名单、限流等功能。
@Slf4j
@Component
public class BlackListFilter implements GlobalFilter, Ordered {
private static List<String> blackList = new ArrayList<>();
static {
blackList.add("0:0:0:0:0:0:0:1"); // 模拟本机地址
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 思路:获取客户端ip,判断是否在⿊名单中,在的话就拒绝访问,不在的话就放⾏
// 从上下⽂中取出request和response对象
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
// 从request对象中获取客户端ip
String clientIp = request.getRemoteAddress().getHostString();
// 拿着clientIp去⿊名单中查询,存在的话就决绝访问
if (blackList.contains(clientIp)) {
// 决绝访问,返回
response.setStatusCode(HttpStatus.UNAUTHORIZED); // 状态码
log.debug("=====>IP:" + clientIp + " 在⿊名单中,将被拒绝访 问!");
String data = "请求被禁止!";
DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
return response.writeWith(Mono.just(wrap));
}
// 合法请求,放⾏,执⾏后续的过滤器
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0; //越小优先级越高
}
}
官方全局过滤器使用规范例子
@RestController
@SpringBootApplication
public class DemogatewayApplication {
@RequestMapping("/hystrixfallback")
public String hystrixfallback() {
return "This is a fallback";
}
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
//@formatter:off
return builder.routes()
.route("path_route", r -> r.path("/get")
.uri("http://httpbin.org"))
.route("host_route", r -> r.host("*.myhost.org")
.uri("http://httpbin.org"))
.route("rewrite_route", r -> r.host("*.rewrite.org")
.filters(f -> f.rewritePath("/foo/(?<segment>.*)",
"/${segment}"))
.uri("http://httpbin.org"))
.route("hystrix_route", r -> r.host("*.hystrix.org")
.filters(f -> f.hystrix(c -> c.setName("slowcmd")))
.uri("http://httpbin.org"))
.route("hystrix_fallback_route", r -> r.host("*.hystrixfallback.org")
.filters(f -> f.hystrix(c -> c.setName("slowcmd").setFallbackUri("forward:/hystrixfallback")))
.uri("http://httpbin.org"))
.route("limit_route", r -> r
.host("*.limited.org").and().path("/anything/**")
.filters(f -> f.requestRateLimiter(c -> c.setRateLimiter(redisRateLimiter())))
.uri("http://httpbin.org"))
.route("websocket_route", r -> r.path("/echo")
.uri("ws://localhost:9000"))
.build();
//@formatter:on
}
@Bean
RedisRateLimiter redisRateLimiter() {
return new RedisRateLimiter(1, 2);
}
@Bean
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) throws Exception {
return http.httpBasic().and()
.csrf().disable()
.authorizeExchange()
.pathMatchers("/anything/**").authenticated()
.anyExchange().permitAll()
.and()
.build();
}
@Bean
public MapReactiveUserDetailsService reactiveUserDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build();
return new MapReactiveUserDetailsService(user);
}
public static void main(String[] args) {
SpringApplication.run(DemogatewayApplication.class, args);
}
}
当然也可以单独做过滤器,比如,黑白名单过滤器,限流,认证,以及token校验等过滤器
import org.apache.commons.chain.Command;
import org.apache.commons.chain.impl.ChainBase;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 责任链模式
* 接口限流->黑名单->白名单->数字签名验证,解码body数据->检查api信息及api参数->远程调用对应的接口->调用结果加密->返回
*/
@Configuration
public class ChainConfig {
@Bean
Command interfaceFlowLimitHandler() {
return new InterfaceFlowLimitHandler();
}
// @Bean
// Command blackIpListCheckHandler() {
// return new BlackIpListCheckHandler();
// }
@Bean
Command whiteIpListCheckHandler() {
return new WhiteIpListCheckHandler();
}
@Bean
Command signatureCheckHandler() {
return new SignatureCheckHandler();
}
@Bean
Command apiInfoCheckHandler() {
return new ApiInfoCheckHandler();
}
@Bean
Command invokeInterfaceHandler() {
return new InvokeInterfaceHandler();
}
@Bean
Command encodeResponseHandler() {
return new EncodeResponseHandler();
}
@Bean
ChainBase chains() {
ChainBase chainBase = new ChainBase();
chainBase.addCommand(interfaceFlowLimitHandler());
chainBase.addCommand(blackIpListCheckHandler());
chainBase.addCommand(whiteIpListCheckHandler());
chainBase.addCommand(signatureCheckHandler());
chainBase.addCommand(apiInfoCheckHandler());
chainBase.addCommand(invokeInterfaceHandler());
chainBase.addCommand(encodeResponseHandler());
return chainBase;
}
}
每个bean类实现Command接口。命令封装要执行的处理工作单元,其目的是检查或修改由上下文表示的事务的状态。单个命令可以被组装成一个链,这允许它们完成所需的处理,或者将进一步的处理委托给链中的下一个命令。命令实现应该以线程安全的方式设计,适合包含在可能由不同线程同时处理的多个链中。
一般来说,这意味着命令类不应该维护实例变量中的状态信息。相反,应该通过对传递给execute()命令的上下文属性的适当修改来维护状态信息。
命令实现通常在上下文实例中检索和存储状态信息,这些信息作为参数传递给execute()方法.
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.apache.commons.chain;
public interface Command {
boolean CONTINUE_PROCESSING = false;
boolean PROCESSING_COMPLETE = true;
boolean execute(Context var1) throws Exception;
}
spring:
application:
name: gateway
cloud:
gateway:
routes:
- id: demo
uri: lb://demo
predicates:
- Path=/rest-web/**
filters:
- StripPrefix=1
Java配置:
代表将 ip地址为10.1.1.1的访问转发到 down。。。。
路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。路由过滤器适用于特定路由。Spring Cloud Gateway包括许多内置的xGatewayFilter工厂。
配置:
spring:
application:
name: gateway
cloud:
gateway:
routes:
- id: demo
uri: lb://demo
predicates:
- Path=/rest-web/**
filters:
- StripPrefix=1 # 将url前缀去掉比如ip,port,http等
- AddRequestHeader=X-Request-red, blue
此清单将X-Request-red:blue标头添加到所有匹配请求的下游请求的标头中。
AddRequestHeader了解用于匹配路径或主机的URI变量。URI变量可以在值中使用,并在运行时扩展。
java config
形式使用ModifyRequestBody过滤器过滤器在网关向下游发送请求主体之前对其进行修改。
尝试通过代码的形式将转发的请求添加头信息:
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("route1", r -> r.path("/payment/nacos/header/**")
.filters(f->f.addRequestHeader("json", "123"))
.uri("lb://nacos-payment-provider")).build();
}
常见的有Zuul、Gateway、Nginx
首先创建父类工程和两个子工程:demo和gateway
父类pom文件定义版本
<modules>
<module>gateway</module>
<module>dubbo-api</module>
<module>rest-web</module>
</modules>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
<spring-cloud-alibaba.version>2.2.2.RELEASE</spring-cloud-alibaba.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
pom.xml
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--nacos 配置中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
</dependencies>
配置文件application.yml
server:
port: 8000
spring:
application:
name: demo
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
简单的controller路由
package com.demo.restweb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
@EnableDiscoveryClient
public class RestWebApplication {
public static void main(String[] args) {
SpringApplication.run(RestWebApplication.class, args);
}
@GetMapping("/demo")
public String demo(String name) {
System.out.println("ssss " + name);
return "hello, " + name + "i am demo";
}
}
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-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
</dependencys>
配置文件application.yml
spring:
application:
name: gateway
cloud:
gateway:
routes:
- id: demo
uri: lb://demo
predicates:
- Path=/rest-web/**
filters:
- StripPrefix=1
nacos:
discovery:
server-addr: 127.0.0.1:8848
enabled: true
访问地址:http://127.0.0.1:8085/rest-web/demo?name=Java技术债务
本文作者:Java技术债务
原文链接:https://www.cuizb.top/myblog/article/1650294609
版权声明: 本博客所有文章除特别声明外,均采用 CC BY 3.0 CN协议进行许可。转载请署名作者且注明文章出处。
JVM内存泄漏和内存溢出的原因
JVM常用监控工具解释以及使用
Redis 常见面试题(一)
ClickHouse之MaterializeMySQL引擎(十)
三种实现分布式锁的实现与区别
线程池的理解以及使用
咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳
最近面试BAT,整理一份面试资料,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。想获取吗?如果你想提升自己,并且想和优秀的人一起进步,感兴趣的朋友,可以在扫码关注下方公众号。资料在公众号里静静的躺着呢。。。
一键四连,你的offer也四连
新浪微博,应该是08年那会推出的,此时国外的twiter正值热火朝天之际,反观国内,那时只有新浪一家在做微博,玩的人不多,蛮冷清的,那会上去玩也是听同学介绍的,不过那会心理面想想,国外twiter那么火,人家老外都在上面玩了,咱也不能落后是不,但twiter又被墙了,而且没中文版,只能是找一款同类型产品替代她,于是就去新浪微博了。咱也来装下逼,。。还有一种心理也在影响着我,“名人”,...
只是一个新手入门级项目,希望新手同学能和我得到学习,大佬请手下留情桌球小游戏项目先放代码和效果图import java.awt.*;import javax.swing.*;public class Ballgame extends JFrame { Image ball=Toolkit.getDefaultToolkit().getImage("images/ball.png"); Image table=Toolkit.getDefaultToolkit().getImage_java开始实战项目
Problem F: Fibonacci AgainTime Limit: 1 Sec Memory Limit: 128 MBSubmit: 64 Solved: 18[Submit][Status][Web Board]DescriptionThere are another kind of Fibonacci numbers: F(0) = 7, F(_f - fibonacci again
本来想尝试自己爬一下全部学生的成绩,结果发现实在是弄不到账号密码,就此作罢。万一有学弟学妹以后想尝试可以参考。import urllibimport urllib2import requestsimport restudent = 八位学号password = 密码postdata = urllib.urlencode({ 'u':student, 'p':password_python北京交通大学选课爬虫
运筹学注:博客:https://blog.csdn.net/badao_liumang_qizhi关注公众号霸道的程序猿获取编程相关电子书、教程推送与免费下载。涉及知识点可能涉及到如下知识点: 规划论:线性规划、非线性规划}、整数规划、目标规划、动态规划 图论与网络 存储论 排队论 决策论 对策论 计算机仿真运筹学中常考的有最短和最长路径问题、线性规划的问题、传输运输学解决资源分配、最小生成树、匈牙利法、最大流量、后悔值的问题求最短和最长..._最小机会损失准则怎么算
要求实现一个简单的导航菜单,没有子菜单。代码如下:<!doctype html><html lang="zh-Han-cmn"><head> <meta charset="UTF-8"> <title>导航栏布局案例</title> <style type="text/css" rel="styleshe..._html导航栏案例
本文主要参考《Go 语言高级编程》一书!发布订阅(publish-and-subscribe)模型通常被简写为 pub/sub 模型。在这个模型中,消息生产者成为发布者(publisher),而消息消费者则成为订阅者(subscriber),生产者和消费者是 M:N 的关系。在传统生产者和消费者模型中,是将消息发送到一个队列中,而发布订阅模型则是将消息发布给一个主题。// Package pu..._go 实现 sub publish
今天,前台的小妹找我帮忙;原因是她的华为手机内存不够用了,请我帮她清理一下。其实,我的内心是抗拒的。虽然,我是做手机软件开发的;但是,我不是修手机的啊。可是,看到她哀求的眼神;我又不忍心拒绝。故,特意写此篇博客丢给她,日后备用。_手机清理输入什么代码
只有愚蠢的人才会相信眼睛看到的。 ——安·兰德故事要从一道贝叶斯定理的简单习题讲起。大意是艾滋病患病率为万分之一,误诊率为5%,患有艾滋病者被诊断出来的概率为99%,请问在这样的设定下如果你被诊断为艾滋病阳性,那么你患艾滋病的概率是多少,原题如下——Problem Denoted blood is screened for AIDS. Suppose the test has 99% acc
第九天:早早的起床本来以为是美好的结束结果车开到一半大家的行李箱都飞出去辽然后教练们都集体下去捡箱子窝还看到mxl那个突出的小肚子上那块地方有泥还有个箱子滚到绿化带那个深沟沟里了qwqlkp的箱子好像还拿错了拿了一个磕的很烂了的打都打不开我发誓我没笑第八天:今天晚上提前去吃饭迎面撞上mxl气势不能输所以就那样走过去了然后前边的路上有泥巴lkx悄悄和我说:咱俩走小路 甩开mxl然后我们就走了小路然后...
用了java 7好几年了,今天闲来无事,想升级到 java 8,到官网下载的时候发现JAVA放出了8u171与8u172两个版本。什么情况?百度一下找到答案:https://blog.csdn.net/u014653815/article/details/80435226这是官方对于奇数版本与偶数版本区别的解释:从JDK版本7u71以后,JAVA将会在同一时间发布两个版本的JDK,..._如何看java是8u多少
1,char,nchar,nvarchar,varchar有什么区别? 2,text和ntext有什么区别以及和上面各种字符类有什么区别? 3,关于带big和带small的类型,比如:smallint,int和bigint;以及smalldatetime,datetime和bigdatetime有什么区别? ========================================...