1.はじめに
春クラウドゲートウェイモジュールの動的ルーティング:この章では、OCPのオープンソースプロジェクトを説明しています。
2.春クラウドゲートウェイ
セキュリティ、監視/指標と弾力性:春クラウドゲートウェイは、APIへのルートに簡単で効果的な方法を提供し、そしてなどの横断的関心事、とそれらを提供するように設計されています。
2.1春クラウドゲートウェイ機能
- 春のフレームワーク5、プロジェクト炉・春ブーツの上に構築された2.0
- 任意のルートは、要求属性を一致させることができます。
- そして、フィルタ述語特定のルート。
- Hystrixは、回路ブレーカを統合しました。
- 春の雲DiscoveryClient集成
- 述語とフィルタを書きやすいです
- リクエストレート制限
- パスの書き換え
2.2プロジェクトの戦闘
次に、私たちは私たちの旅春のクラウドゲートウェイはそれを制限開始します!
2.2.1春クラウドゲートウェイ限流
2.2.2 OCPサブプロジェクトの新しい-API-ゲートウェイ
pom.xml
<!--基于 reactive stream 的redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<!--spring cloud gateway 相关依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
复制代码
2.2.3設定のホスト名を制限するルール
現在は、ユーザーセンターユーザーセンター制限
spring:
cloud:
gateway:
discovery:
locator:
lowerCaseServiceId: true
enabled: true
routes:
# =====================================
- id: api-eureka
uri: lb://eureka-server
order: 8000
predicates:
- Path=/api-eureka/**
filters:
- StripPrefix=1
- name: Hystrix
args:
name : default
fallbackUri: 'forward:/defaultfallback'
- id: api-user
uri: lb://user-center
order: 8001
predicates:
- Path=/api-user/**
filters:
- GwSwaggerHeaderFilter
- StripPrefix=1
- name: Hystrix
args:
name : default
fallbackUri: 'forward:/defaultfallback'
- name: RequestRateLimiter #对应 RequestRateLimiterGatewayFilterFactory
args:
redis-rate-limiter.replenishRate: 1 # 令牌桶的容积 放入令牌桶的容积每次一个
redis-rate-limiter.burstCapacity: 3 # 流速 每秒
key-resolver: "#{@ipAddressKeyResolver}" # SPEL表达式去的对应的bean
复制代码
2.2.4新しい構成クラスRequestRateLimiterConfig
内に配置された新しいクラスcom.open.capacity.client.configパスを
package com.open.capacity.client.config;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;
/**
* 定义spring cloud gateway中的 key-resolver: "#{@ipAddressKeyResolver}" #SPEL表达式去的对应的bean
* ipAddressKeyResolver 要取bean的名字
*
*/
@Configuration
public class RequestRateLimiterConfig {
/**
* 根据 HostName 进行限流
* @return
*/
@Bean("ipAddressKeyResolver")
public KeyResolver ipAddressKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
/**
* 根据api接口来限流
* @return
*/
@Bean(name="apiKeyResolver")
public KeyResolver apiKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getPath().value());
}
/**
* 用户限流
* 使用这种方式限流,请求路径中必须携带userId参数。
* 提供第三种方式
* @return
*/
@Bean("userKeyResolver")
KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
}
}
复制代码
2.2.5ストレステスト
その後、物事は、コンフィギュレーションは、我々が原因新しい-API-gatewayグローバルプレゼンスインターセプターAccessFilterに、圧力試験の前に、ストレステストを開始した後、あなたがテストにログオンしていない場合に行うことを取得します。まず、 "/ API-AUTH / **" 決意でコメントしています。次に、我々はオープン郵便配達でテスト
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// TODO Auto-generated method stub
String accessToken = extractToken(exchange.getRequest());
if(pathMatcher.match("/**/v2/api-docs/**",exchange.getRequest().getPath().value())){
return chain.filter(exchange);
}
if(!pathMatcher.match("/api-auth/**",exchange.getRequest().getPath().value())){
// if (accessToken == null) {
// exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
// return exchange.getResponse().setComplete();
// }else{
// try {
// Map<String, Object> params = (Map<String, Object>) redisTemplate.opsForValue().get("token:" + accessToken) ;
// if(params.isEmpty()){
// exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
// return exchange.getResponse().setComplete();
// }
// } catch (Exception e) {
// exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
// return exchange.getResponse().setComplete();
// }
// }
}
return chain.filter(exchange);
}
复制代码
- 1.郵便配達の選択コレクションは、[新規]ボタンをクリックしてください
-
2.コレクションの新しい要求を作成するには、[新規]をクリックします
-
- 127.0.0.1:9200 / API-ユーザー/ユーザー・アノン/ログインユーザ名=管理者アドレスを入力してください?
- タブの4試験は、右下の選択されたに切り換えられる状態コード200である他の方法は、その定義APIに応じて適宜選択することができるオプション。
- 5.なお:データが終了したばかり、あなたはそれ以外の場合は、効果的なことができませんでした、保存するために[保存]をクリックしなければなりません。 要求の設定
-
- あなたは結果を表示することができ、ファイル名を指定して実行]をクリックし、成功した5があり、5人が失敗した; 429の成功したリターンを制限します
前の章では、我々は単純泉クラウドゲートウェイと制限導入、次の最も重要な、そして最も重要な春のクラウドゲートウェイ行っているダイナミックルーティングすべての最初に、APIゲートウェイは、サービス要求のルーティング、プロトコル変換と組み合わせ、顧客のために責任があります新しいがある場合は、すべての要求は第1のゲートウェイAPI後に終了している、それは適切なマイクロサービスにルーティング要求と一致しますが、このシステムは、高い信頼性と再起動を回避するために、を確保するために、本番環境での流入でありますときにオンラインへのサービスは、あなたがダイナミックルーティングを通じて機能ラインを設定することができます。
3.春クラウドゲートウェイ、ダイナミックルーティングを達成するために
まず、二つの方法でルーティングを設定springcloudgateway:
- YMLプロフィール
- オブジェクトの設定(コンフィギュレーションモードコード)について
3.1 YMLの設定
3.2コードモードの設定
3.3ルーティング初期化
クラウド・ゲートウェイ・ゲートウェイの起動、メモリにロードされたデフォルトルーティング情報をsrping場合、ルーティング情報はにカプセル化されRouteDefinitionの、オブジェクト
org.springframework.cloud.gateway.route.RouteDefinition
复制代码
そのような特性のいくつかは以下のとおりです。
@NotEmpty
private String id = UUID.randomUUID().toString();
//路由断言定义
@NotEmpty
@Valid
private List<PredicateDefinition> predicates = new ArrayList<>();
//路由过滤定义
@Valid
private List<FilterDefinition> filters = new ArrayList<>();
//对应的URI
@NotNull
private URI uri;
private int order = 0;
复制代码
RouteDefinitionが指定されていない場合、デフォルトはUUIDで、一意のIDを有し、よりRouteDefinitionゲートウェイルーティングシステムを形成し、すべてのルーティング情報は、システム起動時にロードされ、組み立て、およびメモリにそれらを保存しました。
3.4ゲートウェイが自動的に構成します
org.springframework.cloud.gateway.config.GatewayAutoConfiguration
复制代码
//RouteLocatorBuilder 采用代码的方式注入路由
@Bean
public RouteLocatorBuilder routeLocatorBuilder(ConfigurableApplicationContext context) {
return new RouteLocatorBuilder(context);
}
//PropertiesRouteDefinitionLocator 配置文件路由定义
@Bean
@ConditionalOnMissingBean
public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(GatewayProperties properties) {
return new PropertiesRouteDefinitionLocator(properties);
}
//InMemoryRouteDefinitionRepository 内存路由定义
@Bean
@ConditionalOnMissingBean(RouteDefinitionRepository.class)
public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository() {
return new InMemoryRouteDefinitionRepository();
}
//CompositeRouteDefinitionLocator 组合多种模式,为RouteDefinition统一入口
@Bean
@Primary
public RouteDefinitionLocator routeDefinitionLocator(List<RouteDefinitionLocator> routeDefinitionLocators) {
return new CompositeRouteDefinitionLocator(Flux.fromIterable(routeDefinitionLocators));
}
@Bean
public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,
List<GatewayFilterFactory> GatewayFilters,
List<RoutePredicateFactory> predicates,
RouteDefinitionLocator routeDefinitionLocator) {
return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, GatewayFilters, properties);
}
//CachingRouteLocator 为RouteDefinition提供缓存功能
@Bean
@Primary
//TODO: property to disable composite?
public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
return new CachingRouteLocator(new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
}
复制代码
YMLアセンブリファイルは、それがPropertiesRouteDefinitionLocatorを返し、クラスがRouteDefinitionLocatorを継承し、RouteDefinitionLocatorはローダーをルーティングしている、唯一の方法は、ルーティング情報を取得することであります。
org.springframework.cloud.gateway.route.RouteDefinitionLocator
复制代码
RouteDefinitionLocatorのクラス図は次のとおりです。
サブクラスの関数の説明:
- CachingRouteDefinitionLocator:RouteDefinitionLocator包装、キャッシュ対象routeDefinitionsのキャッシング機能を提供RouteDefinitionLocator
- CompositeRouteDefinitionLocator -RouteDefinitionLocator包装、RouteDefinitionLocatorを達成するための様々な組み合わせは、統一入学routeDefinitionsを提供します
- PropertiesRouteDefinitionLocator- RouteDefinitionは、コンフィギュレーションファイル(GatewayProperties例えば、YML /プロパティ、等)から読み出し
- RouteDefinitionRepository- RouteDefinitionがメモリから読み出された(例えば、メモリ/等のRedis / MySQLの)
- レジストリからDiscoveryClientRouteDefinitionLocator-(例えば、ユーレカ/コンサル/飼育係/ Etcd等
推奨参考記事:www.jianshu.com/p/b02c7495e ...
3.5をルーティングダイナミック書きます
新しいデータスクリプトSQL 02.oauth-center.sqlディレクトリ
#
# Structure for table "sys_gateway_routes"
#
DROP TABLE IF EXISTS sys_gateway_routes;
CREATE TABLE sys_gateway_routes
(
`id` char(32) NOT NULL COMMENT 'id',
`uri` VARCHAR(100) NOT NULL COMMENT 'uri路径',
`predicates` VARCHAR(1000) COMMENT '判定器',
`filters` VARCHAR(1000) COMMENT '过滤器',
`order` INT COMMENT '排序',
`description` VARCHAR(500) COMMENT '描述',
`delFlag` int(11) DEFAULT '0' COMMENT '删除标志 0 不删除 1 删除',
`createTime` datetime NOT NULL,
`updateTime` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8mb4 COMMENT '服务网关路由表';
复制代码
/**
* 路由实体类
*/
public class GatewayRoutes {
private String id;
private String uri;
private String predicates;
private String filters;
private Integer order;
private String description;
private Integer delFlag;
private Date createTime;
private Date updateTime;
//省略getter,setter
}
复制代码
/**
* 路由的Service类
*/
@Service
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware, IDynamicRouteService {
/**
* 新增路由
*
* @param gatewayRouteDefinition
* @return
*/
@Override
public String add(GatewayRouteDefinition gatewayRouteDefinition) {
GatewayRoutes gatewayRoutes = transformToGatewayRoutes(gatewayRouteDefinition);
gatewayRoutes.setDelFlag(0);
gatewayRoutes.setCreateTime(new Date());
gatewayRoutes.setUpdateTime(new Date());
gatewayRoutesMapper.insertSelective(gatewayRoutes);
gatewayRouteDefinition.setId(gatewayRoutes.getId());
redisTemplate.opsForValue().set(GATEWAY_ROUTES_PREFIX + gatewayRouteDefinition.getId(), JSONObject.toJSONString(gatewayRouteDefinition));
return gatewayRoutes.getId();
}
/**
* 修改路由
*
* @param gatewayRouteDefinition
* @return
*/
@Override
public String update(GatewayRouteDefinition gatewayRouteDefinition) {
GatewayRoutes gatewayRoutes = transformToGatewayRoutes(gatewayRouteDefinition);
gatewayRoutes.setCreateTime(new Date());
gatewayRoutes.setUpdateTime(new Date());
gatewayRoutesMapper.updateByPrimaryKeySelective(gatewayRoutes);
redisTemplate.delete(GATEWAY_ROUTES_PREFIX + gatewayRouteDefinition.getId());
redisTemplate.opsForValue().set(GATEWAY_ROUTES_PREFIX + gatewayRouteDefinition.getId(), JSONObject.toJSONString(gatewayRouteDefinition));
return gatewayRouteDefinition.getId();
}
/**
* 删除路由
* @param id
* @return
*/
@Override
public String delete(String id) {
gatewayRoutesMapper.deleteByPrimaryKey(id);
redisTemplate.delete(GATEWAY_ROUTES_PREFIX + id);
return "success";
}
}
复制代码
/**
* 核心类
* getRouteDefinitions() 通过该方法获取到全部路由,每次有request过来请求的时候,都会往该方法过。
*
*/
@Component
public class RedisRouteDefinitionRepository implements RouteDefinitionRepository {
public static final String GATEWAY_ROUTES_PREFIX = "geteway_routes_";
@Autowired
private StringRedisTemplate redisTemplate;
private Set<RouteDefinition> routeDefinitions = new HashSet<>();
/**
* 获取全部路由
* @return
*/
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
/**
* 从redis 中 获取 全部路由,因为保存在redis ,mysql 中 频繁读取mysql 有可能会带来不必要的问题
*/
Set<String> gatewayKeys = redisTemplate.keys(GATEWAY_ROUTES_PREFIX + "*");
if (!CollectionUtils.isEmpty(gatewayKeys)) {
List<String> gatewayRoutes = Optional.ofNullable(redisTemplate.opsForValue().multiGet(gatewayKeys)).orElse(Lists.newArrayList());
gatewayRoutes
.forEach(routeDefinition -> routeDefinitions.add(JSON.parseObject(routeDefinition, RouteDefinition.class)));
}
return Flux.fromIterable(routeDefinitions);
}
/**
* 添加路由方法
* @param route
* @return
*/
@Override
public Mono<Void> save(Mono<RouteDefinition> route) {
return route.flatMap(routeDefinition -> {
routeDefinitions.add( routeDefinition );
return Mono.empty();
});
}
/**
* 删除路由
* @param routeId
* @return
*/
@Override
public Mono<Void> delete(Mono<String> routeId) {
return routeId.flatMap(id -> {
List<RouteDefinition> collect = routeDefinitions.stream().filter(
routeDefinition -> StringUtils.equals(routeDefinition.getId(), id)
).collect(Collectors.toList());
routeDefinitions.removeAll(collect);
return Mono.empty();
});
}
}
复制代码
/**
* 编写Rest接口
*/
@RestController
@RequestMapping("/route")
public class RouteController {
@Autowired
private IDynamicRouteService dynamicRouteService;
//增加路由
@PostMapping("/add")
public Result add(@RequestBody GatewayRouteDefinition gatewayRouteDefinition) {
return Result.succeed(dynamicRouteService.add(gatewayRouteDefinition));
}
//更新路由
@PostMapping("/update")
public Result update(@RequestBody GatewayRouteDefinition gatewayRouteDefinition) {
return Result.succeed(dynamicRouteService.update(gatewayRouteDefinition));
}
//删除路由
@DeleteMapping("/{id}")
public Result delete(@PathVariable String id) {
return Result.succeed(dynamicRouteService.delete(id));
}
}
复制代码
筆記試験3.6ダイナミックルーティング
GET localhost:9200/actuator/gateway/routes
复制代码
1.ゲートウェイを参照して、すべてのルート、テスト対象のルートを、このインターフェイスを使用して/ JDを/ * *見つかりませんでした
POST 127.0.0.1:9200/route/add
复制代码
フォーマット型com.open.capacity.client.dto.GatewayRouteDefinitionに対応するパラメータから構築JSON
{
"id": "",
"uri": "lb://user-center",
"order": 1111,
"filters": [
{
"name": "StripPrefix",
"args": {
"_genkey_0": "1"
}
}
],
"predicates": [
{
"name": "Path",
"args": {
"_genkey_0": "/jd/**"
}
}
],
"description": "测试路由新增"
}
复制代码
正常に追加され、mysqlの参照、対応するIDを返し、Redisのは正常に保存されています
ちょうどルーティングインターフェイスのすべてへのアクセスを取得するには、私たちの** / JDは/ ****すでに私たちのゲートウェイに登録見つけます
GET localhost:9200/jd/users-anon/login?username=admin
复制代码
この時間は、我々はプロジェクトを再起動する必要はありません、あなたはまだルートたちのカスタムにアクセスすることができ、これには、我々はまた、操作、それに続く、削除、更新を完了している、それは単に完全に下APIを呼び出すことです!
プラン焦点
オープンソース・プロジェクトからのより多くのOCP:gitee.com/owenwangwen ...
プロジェクトのデモhttp://59.110.164.254:8066/login.htmlユーザー名/パスワード:管理者/管理者
プロジェクトの監視http://106.13.3.200:3000ユーザー名/パスワード:管理者/ 1q2w3e4r
商品コードアドレスgitee.com/owenwangwen ...
グループ番号:483 725 710(注:コーダプログラミング)が参加を歓迎します〜
文末
個人的なマイクロチャネル公衆番号へようこそ注意:Coderのプログラムの最新オリジナルな技術に関する記事と無料の学習教材のため、多くのブティックマインドマップ、インタビューデータ、PMPの準備資料あなたがリードするために、待っているあなたは、いつでも、どこでも技術的な知識を習得することができます!
ようこそ注意と星〜