在微服务架构中,我们会遇到这样的问题:1.在调用微服务时,需要鉴权,微服务不能任意给外部调用。但是,多个微服务如果都需要同一套鉴权规则,明显会产生冗余,如果鉴权方法需要修改,则需要改动多个地方。2.在前端调用服务的时候,前端需要根据不同的服务配置,找到对于服务的IP,端口等信息,才能完成对应调用。如果中间有修改或者有扩展时,这会显得很麻烦,尤其是在微服务越来越多的时候。
有没有一种方式,提供一个统一的入口,统一鉴权,配置路由,解决上面两个问题?Spring Cloud Gateway为我们提供了很好的解决方案。在Finchley版本之前,Spring Cloud使用netflix的Zuul完成类似的功能。在Finchley之后,我们更推荐使用Spring Cloud自行开发的Gateway,Gateway对比Zuul 1.0具有更好的性能和集成性。
该项目提供了一个建立在Spring Ecosystem之上的API网关,包括:Spring 5,Spring Boot 2和Project Reactor。Spring Cloud Gateway旨在提供一种简单而有效的方式来路由到API,并为他们提供横切关注点,例如:安全性,监控/指标和弹性。
01.配置使用
添加gateway依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
02.工作流程
image.png客户端向Spring Cloud Gateway发出请求。如果网关处理程序映射确定请求与路由匹配,则将其发送到网关Web处理程序。此处理程序运行通过特定于请求的过滤器链发送请求。滤波器被虚线划分的原因是滤波器可以在发送代理请求之前或之后执行逻辑。执行所有“预”过滤器逻辑,然后进行代理请求。在发出代理请求之后,执行“post”过滤器逻辑。
03.详细配置
1.路由谓词工厂(具体的配置和说明已注释到代码中)
spring: application: name: gateway-service cloud: gateway: routes: #指定时间前的路由地址 - id: before_route uri: http://www.baidu.com predicates: - Before=2017-01-20T17:42:47.789-07:00 #指定时间之间的路由地址 - id: before_route uri: http://www.sohu.com predicates: - Between=2020-01-20T17:42:47.789-07:00,2020-01-21T17:42:47.789-07:00 #指定时间后的路由地址 - id: before_route uri: http://www.sina.com predicates: - After=2019-05-20T17:42:47.789-07:00 #指定Cookie中有指定值的路由地址,这里注意有两个参数,第一个为Cookie的Key,第二个为正则表达式 - id: cookie_route uri: http://www.qq.com predicates: - Cookie=chocolate,[A-Za-z]+ #指定Header中有指定值的路由地址,有两个参数,第一个为Header的Key,第二个为正则表达式 - id: header_route uri: http://www.163.com predicates: - Header=X-Request-Id, \d+ #指定Host的路由 - id: host_route uri: http://www.360.com predicates: - Host=**.somehost.org,**.anotherhost.org #指定请求方法的路由 - id: method_route uri: http://www.baidu.com predicates: - Method=GET #segment作为参数,可以在接口后台获取 - id: params_route uri: lb://test-client-service predicates: - Path=/test/{segment} filters: #SetPath filter 使用模版参数,修改请求路径 - SetPath=/{segment} #AddRequestHeader过滤器添加Request头 - AddRequestHeader=X-Request-Foo, Bar #ip地址控制路由,192.168.1.1 - id: remoteaddr_route uri: http://localhost:8090 predicates: - RemoteAddr=192.168.1.1 #url中带有params查询的,如:http://localhost:9005/getUser?params=111,params后还可以加正则表达式,如:params,\d+ - id: query_route uri: lb://test-client-service predicates: - Query=params
2.过滤工厂
路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应,路径过滤器的范围限定为特定路径。
#以下为过滤工厂,过滤工厂与谓词工厂同级 filters: #AddRequestHeader过滤器添加Request头 - AddRequestHeader=X-Request-Foo, Bar #AddRequestParameter过滤器添加参数头 - AddRequestParameter=bar, barValue #AddResponseHeader过滤器添加返回Response头 - AddResponseHeader=X-Response-Foo, 123 #PrefixPath添加前缀,如请求为/getUser,则会转成/mypath/getUser #- PrefixPath=/mypath #往exchange添加PRESERVE_HOST_HEADER_ATTRIBUTE - PreserveHostHeader #结合redis限流 #redis-rate-limiter.replenishRate:允许用户每秒处理多少个请求 #redis-rate-limiter.burstCapacity:令牌桶的容量,允许在一秒钟内完成的最大请求数 - name: RequestRateLimiter args: key-resolver: "#{@remoteAddrKeyResolver}" redis-rate-limiter.replenishRate: 1 redis-rate-limiter.burstCapacity: 5 #RedirectTo 重定向,第一个参数是状态码,必须是3xx,第二个参数是要重定向的地址 #- RedirectTo=302, http://www.baidu.com #删除NonProxy头信息,默认删除 #Connection #Keep-Alive #Proxy-Authenticate #Proxy-Authorization #TE #Trailer #Transfer-Encoding #Upgrade #可以通过spring.cloud.gateway.filter.remove-non-proxy-headers.headers配置要删除得到头信息 - RemoveNonProxyHeaders #RemoveRequestHeader 删除指定头信息filter - RemoveRequestHeader=X-Request-Foo #RemoveResponseHeader 删除返回头信息filter - RemoveResponseHeader=X-Response-Foo #RewritePath过滤工厂,下面这个写法的意思是把请求都带上前缀/foo,如请求是/example,则真正到达后台的请求会变成/foo/example - RewritePath=/(?<segment>.*), /foo/$\{segment} #RewriteResponseHeader 重写ResponseHeader,三个参数,第一个是头的key值,第二个是需要替换的值,第三个是替换后的值,其中第二个参数可以使用正则表达式来匹配 - RewriteResponseHeader=X-Response-Foo, 123, 321 #SaveSession 会话保存过滤器 - SaveSession #SecureHeaders 默认往返回的response添加以下header,可以通过配置spring.cloud.gateway.filter.secure-headers 修改需要添加的header # X-Xss-Protection:1; mode=block # Strict-Transport-Security:max-age=631138519 # X-Frame-Options:DENY # X-Content-Type-Options:nosniff # Referrer-Policy:no-referrer # Content-Security-Policy:default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline' # X-Download-Options:noopen # X-Permitted-Cross-Domain-Policies:none - SecureHeaders #SetResponseHeader ,修改responseHeader - SetResponseHeader=X-Response-Foo1, modifyValue #SetStatus 设置返回的状态,可以是code(如404,401,403),也可以是对应的描述(注意描述中间的空格要用下划线替换) - SetStatus=BAD_GATEWAY #StripPrefix 除去请求的前X位,如X是2且请求是/1/2/3,则最终请求是/3,如X是2且请求是/1,则最终请求是/ - StripPrefix=0 #Retry 重试机制 #retries,默认为3,用来标识重试次数 #series,用来指定哪些段的状态码需要重试,默认SERVER_ERROR即5xx #statuses,用于指定哪些状态需要重试,默认为空,它跟series至少得指定一个 #methods,用于指定那些方法的请求需要重试,默认为GET #exceptions,用于指定哪些异常需要重试,默认为java.io.IOException - name: Retry args: retries: 3 series: - SERVER_ERROR methods: - GET - POST exceptions: - java.lang.RuntimeException # RequestSize 请求最大size - name: RequestSize args: maxSize: 1000
3.Hystrix过滤工厂
Hystrix是Netflix的一个库,它实现了断路器模式。Hystrix GatewayFilter允许您将断路器引入网关路由,保护您的服务免受级联故障的影响,并允许您在下游故障时提供回退响应。
#Hystrix gateway过滤器工厂,需要引入hystrix包,当请求服务超时时,请求gateway本地的fallback接口 - name: Hystrix args: name: fallbackcmd fallbackUri: forward:/fallback - id: ingredients-fallback uri: lb://hystrix-service predicates: - Path=/fallback filters: - name: FallbackHeaders args: executionExceptionTypeHeaderName: Test-Header #此配置可配置gateway请求的超时时间 #hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds: 5000 - Hystrix=testHystrixExtendsCommandService
转自:https://www.jianshu.com/p/dabf2d91fd6e