上一篇:如何保证微服务接口的安全? | 带你读《Spring Cloud Alibaba(2019)》之十一
下一篇:什么是SpringCloud Sentinel | 带你读《Spring Cloud Alibaba(2019)》之十三
本文来自于《精通Spring Cloud Alibaba》课程的整理,讲师为余胜军,点击查看视频内容。
本文系志愿者整理,供配合学习中心课程使用,不做商业用途。
动态请求参数网关
动态网关:任何配置都实现不用重启网关服务器都可以及时刷新网关配置。
方案:
1.基于数据库形式实现,特别建议,阅读性高
2.基于配置中心实现,不建议使用,需要定义json格式配置,阅读性差
注意:配置中心实现维护性比较差,建议采用数据库形式设计。
基于数据库表形式的设计
网关已经提供了API接口
1、直接新增
2、直接修改
思路:
默认加载时候
1、当我们的网关服务启动的时候,从我们数据库查询网关的配置。
2、将数据库的内容读取到网关内存中
网关配置要更新的时候,需要同步调用
伪代码步骤:
1、更新数据库
2、调用网关api更新
网关服务相关表
CREATE TABLE `mayikt_gateway` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`route_id` varchar(11) DEFAULT NULL,
`route_name` varchar(255) DEFAULT NULL,
`route_pattern` varchar(255) DEFAULT NULL,
`route_type` varchar(255) DEFAULT NULL,
`route_url` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
代码实现动态服务网关过程
public class GatewayService implements ApplicationEventPublisherAware {
private ApplicationEventPublisher publisher;
@Autowired
private RouteDefinitionWriter routeDefinitionWriter;
@Autowired
private MayiktGatewayMapper mayiktGateway;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
public void initAllRoute() {
// 从数据库查询配置的网关配置
List<GateWayEntity> gateWayEntities = mayiktGateway.gateWayAll();
for (GateWayEntity gw :
gateWayEntities) {
loadRoute(gw);
}
}
public String loadRoute(GateWayEntity gateWayEntity) {
RouteDefinition definition = new RouteDefinition();
Map<String, String> predicateParams = new HashMap<>(8);
PredicateDefinition predicate = new PredicateDefinition();
FilterDefinition filterDefinition = new FilterDefinition();
Map<String, String> filterParams = new HashMap<>(8);
// 如果配置路由type为0的话 则从注册中心获取服务
URI uri = null;
if (gateWayEntity.getRouteType().equals("0")) {
URI uri = UriComponentsBuilder.fromUriString("lb://" + gateWayEntity.getRouteUrl() + "/").build().toUri();
} else {
uri = UriComponentsBuilder.fromHttpUrl(gateWayEntity.getRouteUrl()).build().toUri();
}
// 定义的路由唯一的id
definition.setId(gateWayEntity.getRouteId());
predicate.setName("Path");
//路由转发地址
predicateParams.put("pattern", gateWayEntity.getRoutePattern());
predicate.setArgs(predicateParams);
// 名称是固定的, 路径去前缀
filterDefinition.setName("StripPrefix");
filterParams.put("_genkey_0", "1");
filterDefinition.setArgs(filterParams);
definition.setPredicates(Arrays.asList(predicate));
definition.setFilters(Arrays.asList(filterDefinition));
definition.setUri(uri);
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "success";
}
}
实体类&访问层
public interface MayiktGatewayMapper {
@Select("SELECT ID AS ID, route_id as routeid, route_name as routeName,route_pattern as routePattern\n" +
",route_type as routeType,route_url as routeUrl\n" +
" FROM mayikt_gateway\n")
public List<GateWayEntity> gateWayAll();
@Update("update mayikt_gateway set route_url=#{routeUrl} where route_id=#{routeId};")
public Integer updateGateWay(@Param("routeId") String routeId, @Param("routeUrl") String routeUrl);
}
Maven依赖
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<!-- mysql 依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 阿里巴巴数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.14</version>
</dependency>
### 127.0.0.1/mayikt 转到到http://www.mayikt.com/
datasource:
url: jdbc:mysql://localhost:3306/meite_gateWay?useUnicode=true&characterEncoding=UTF-8
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
我们刷新一下,传入token,可以看到:
GateWay的词汇表有那些
路由:是网关基本的模块,分别为id(唯一)、目标uri(真实服务地址)、一组谓词+过滤器一起组合而成,如果谓词匹配成功,则路由匹配成功。
谓词: 匹配Http请求参数
过滤器:对下游的服务器之前和之后实现处理。
1、匹配时间之后
- id: mayikt
uri: http://www.mayikt.com/
###匹配规则
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
此路由与 2017 年 1 月 20 日 17:42 MountainTime(Denver)之后的所有请求相匹配。
2、匹配对应的host
- id: meite
uri: http://www.mayikt.com/
###匹配规则
predicates:
- Host=meite.mayikt.com
访问 mete.mayikt.com 转发到http://www.mayikt.com/
3、权重谓词
- id: weight_high
uri: http://www.mayikt.com/yushengjun
predicates:
- Weight=group1, 2
- id: weight_low
uri: http://www.mayikt.com
predicates:
- Weight=group1, 1
根据权重比例实现转发
- id: weight_order
uri: lb://meitemayikt-order
predicates:
- Weight=group1,2
- id: weight_member
uri: lb://mayikt-member
predicates:
- Weight=group1,1
详细参考:
https://cloud.spring.io/spring-cloud-gateway/reference/html/#gatewayfilter-factories
GateWay解决跨域的问题
*/
@Component
public class CrossOriginFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
HttpHeaders headers = response.getHeaders();
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "POST, GET, PUT, OPTIONS, DELETE, PATCH");
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "*");
headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
return chain.filter(exchange);
}
}
网关GateWay源码分析
1.客户端向网关发送Http请求,会到达DispatcherHandler接受请求,匹配到
RoutePredicateHandlerMapping。
- 根据RoutePredicateHandlerMapping匹配到具体的路由策略。
- FilteringWebHandler获取的路由的GatewayFilter数组,创建 GatewayFilterChain 处理过滤请求
- 执行我们的代理业务逻辑访问。
常用配置类说明:
- GatewayClassPathWarningAutoConfiguration 检查是否有正确的配置webflux
- GatewayAutoConfiguration 核心配置类
- GatewayLoadBalancerClientAutoConfiguration 负载均衡策略处理
- GatewayRedisAutoConfiguration Redis+lua整合限流
常见错误
Parameter 0 of method modifyRequestBodyGatewayFilterFactory in org.springframework.cloud.gateway.config.GatewayAutoConfiguration required a bean of type 'org.springframework.http.codec.ServerCodecConfigurer' that could not be found.
原因就是
SpringCloud gateway基于webflux实现的,不是基于SpringBoot-web,所以应该删除
SpringBoot-web依赖组件。
SpringCloud gateway 常用名词
Route 路由 路由的id (唯一)、 转发uri (真实服务地址)、过滤器、谓词组成。
谓词 匹配的规则
源码分析:
SpringBoot项目源码的入口
- GatewayClassPathWarningAutoConfiguration 作用检查是否配置我们webfux依赖。
- GatewayAutoConfiguration加载了我们Gateway需要的注入的类。
- GatewayLoadBalancerClientAutoConfiguration 网关需要使用的负载均衡
Lb//mayikt-member// 根据服务名称查找真实地址 - GatewayRedisAutoConfiguration 网关整合Redis整合Lua实现限流
- GatewayDiscoveryClientAutoConfiguration 服务注册与发现功能
微服务中跨域的问题 不属于前端解决,jsonp 只能支持get请求。
核心点就是在我们后端。
解决跨域的问题
- HttpClient转发
- 使用过滤器允许接口可以跨域 响应头设置
- Jsonp 不支持我们的post 属于前端解决
- Nginx解决跨域的问题保持我们域名和端口号一致性
- Nginx也是通过配置文件解决跨域的问题
- 基于微服务网关解决跨域问题,需要保持域名和端口一致性
- 使用网关代码允许所有的服务可以跨域的问题
- 使用SpringBoot注解形式@CrossOrigin