结合E:\Codes\Idea_java_works\apesource\springboot\微服务\springboot_gateway
简介
在此之前,我们调用服务需要记忆不同的端口号,非常麻烦,使用gateway网关就可以直接访问网关的端口号,
让网关在nacos中寻找服务,并且转发到相对应服务的端口号。
Gateway服务⽹关 Spring Cloud Gateway 是 Spring Cloud 的⼀个全新项⽬,该项⽬是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等响应式编程和事件流技术开发的⽹关,它旨在为微服务架构提供 ⼀种简单有效的统⼀的 API 路由管理⽅式。
操作流程
- 创建gateway服务,引⼊依赖 创建服务: 创建⼀个 api-gateway 的模块,导⼊相关依赖
XML
<!--⽹关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<!--nacos服务发现依赖(gateway⾼级使⽤需要)-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
-
编写api-gateway的配置文件
#########################高级版本##################################
#启动类添加注解@EnabLeDiscoveryClient,项目添加坐标
server:
port: 7000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
discovery:
locator:
enabled: true # 让gateway可以发现nacos中的微服务
routes: # 路由数组[路由就是指定当请求满⾜什么条件的时候转到哪个微服务]
- id: product_route
uri: lb://server-product # 指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
order: 1 # 路由优先级 数字越低优先级越高
predicates: # 断言
- Path=/product/** # 当请求路径满⾜Path指定的规则时,才进⾏路由换发
filters:
- StripPrefix=1 # 拼接好url之后去掉1层路径也就是product
- AddRequestHeader=msg,abc
- id: order_route
uri: lb://server-order # 指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
order: 1 # 路由优先级 数字越低优先级越高
predicates: # 断言
- Path=/order/** # 当请求路径满⾜Path指定的规则时,才进⾏路由换发
filters:
- StripPrefix=1 # 拼接好url之后去掉1层路径也就是product
- AddRequestHeader=msg,abc -
发送请求测试
- 例如之前发的是localhost:8080/product/1
- 现在就是 localhost:7000/product/product/1
断言工厂
例如Path=/user/**是按照路径匹配,这个规则是由org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory类来处理 的,像这样的断⾔⼯⼚在SpringCloudGateway还有⼗⼏个:
|------------|--------------------|-----------------------------------------------------------------------------------------------------------|
| 名称 | 说明 | 示例 |
| After | 是某个时间点后的请求 | -After=2037-01-20T17:42:47.789-07:0o[America/Denver] |
| Before | 是某个时间点之前的请求 | - Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai] |
| Between | 是某两个时间点之前的请求 | -Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver] |
| Cookie | 请求必须包含某些cookie | -Cookie=chocolate, ch.p |
| Header | 请求必须包含某些header | -Header=X-Request-Id, \d+ |
| Host | 请求必须是访问某个host (域名) | -Host=.somehost.org,.anotherhost.org |
| Method | 请求方式必须是指定方式 | -Method=GET,POST |
| Path | 请求路径必须符合指定规则 | -Path=/red/{segment},/blue/** |
| Query | 请求参数必须包含指定参 | -Query=name,Jack或者-Query=name |
| RemoteAddr | 请求者的ip必须是指定范围 | -RemoteAddr=192.168.1.1/25 |
| Weight | 权重处理 | |
过滤器工厂
GatewayFilter是⽹关中提供的⼀种过滤器,可以对进⼊⽹关的请求和微服务返回的响应做处理:
|----------------------|----------------|
| 名称 | 说明 |
| AddRequestHeader | 给当前请求添加一个请求头 |
| RemoveRequestHeader | 移除请求中的一个请求头 |
| AddResponseHeader | 给响应结果中添加一个响应头 |
| RemoveResponseHeader | 从响应结果中移除有一个响应头 |
| RequestRateLimiter | 限制请求的流量 |
路由过滤器(当前路由的过滤器)
routes: # 路由数组[路由就是指定当请求满⾜什么条件的时候转到哪个微服务]
- id: product_route
uri: lb://server-product # 指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
order: 1 # 路由优先级 数字越低优先级越高
predicates: # 断言
- Path=/product/** # 当请求路径满⾜Path指定的规则时,才进⾏路由换发
filters:
- StripPrefix=1 # 拼接好url之后去掉1层路径也就是product
java
@GetMapping("/{id}")
public Product selectById(@PathVariable int id) {
Product product = service.getById(id);
log.info(product.toString());
return product;
}
默认过滤器(范围是所有路由,但是只能使用默认提供的过滤规则)
举例AddRequestHeader
配置文件
routes: # 路由数组[路由就是指定当请求满⾜什么条件的时候转到哪个微服务]
- id: product_route
uri: lb://server-product # 指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
order: 1 # 路由优先级 数字越低优先级越高
predicates: # 断言
- Path=/product/** # 当请求路径满⾜Path指定的规则时,才进⾏路由换发
filters:
- StripPrefix=1 # 拼接好url之后去掉1层路径也就是product
default-filters: # 默认过滤器 范围全局
- AddRequestHeader=msg,abc
Handler
java
@GetMapping("/{id}")
public Product selectById(@PathVariable int id,@RequestHeader(value = "msg") String msg) {
Product product = service.getById(id);
System.out.println(msg);
System.out.println(msg);
System.out.println(msg);
System.out.println(msg);
System.out.println(msg);
log.info(product.toString());
return product;
}
全局过滤器-登录校验(范围是所有路由,可以自定义过滤规则,拦截未登录用户)
- 登录状态判断
- 权限校验
- 请求限流等
需求:定义全局过滤器,拦截请求,判断请求的参数是否满⾜下⾯条件:
● 参数中是否有authorization, authorization参数值是否为admin
●如果同时满⾜则放⾏,否则拦截 实现:在gateway中定义⼀个过滤器:
java
package com.ape.apigateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
//导入IOC就可以生效
@Component
@Order(-1) // 用来控制优先级 数字越小优先级越高
public class AuthorizeFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().get("authorization").get(0);
if (token.equals("admin")){
// 放行
return chain.filter(exchange);
}
// 拦截 禁止访问
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
}
过滤器执行顺序
默认===》路由===》全局
跨域解决方案
跨域:域名不⼀致就是跨域,主要包括:
- 域名不同: www.taobao.com 和 www.taobao.org 和 www.jd.com 和 miaosha.jd.com
- 域名相同,端⼝不同:localhost:8080和localhost8081
跨域问题:浏览器禁⽌请求的发起者与服务端发⽣跨域ajax请求,请求被浏览器拦截的问题
CORS是跨源资源分享(Cross-Origin Resource Sharing)的缩写。它是W3C标准,是跨源AJAX请求 的根本解决⽅法。相⽐JSONP只能发GET请求,CORS允许任何类型的请求。 在gateway服务的application.yml⽂件中,添加下⾯的配置:
spring:
cloud:
gateway:
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
corsConfigurations:
'[/**]':
allowedOrigins: # 允许哪些⽹站的跨域请求
- "http://localhost:8090"
allowedMethods: # 允许的跨域ajax的请求⽅式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期