底层使用Netty框架,性能大于Zuuljavascript
配置gateway模块,通常使用yaml格式:html
server: port: 80 #spring boot actuator服务监控端点 management: endpoint: health: show-details: always endpoints: jmx: exposure: include: '*' web: exposure: include: '*' health: sentinel: enabled: false spring: application: name: spring-cloud-gateway cloud: gateway: discovery: locator: enabled: true #启用DiscoveryClient网关集成的标志,能够实现服务的发现 #gateway 定义路由转发规则 routes: #一份设定 - id: route1 #惟一标识 uri: lb://nacos-discovery-provider #访问的路径,lb://负载均衡访问固定写法,经过负载均衡调取全部设定中的一份 predicates: #谓词,判断,是否匹配。用户请求的路径是否与...进行匹配,若是匹配则能够访问,不然就404 - Path=/test,/index - id: route2 uri: lb://nacos-discovery-provider predicates: - Path=/test*/** - id: route3 uri: lb://nacos-discovery-provider predicates: - Path=/service/** #过滤器 filters: - AddRequestHeader=X-Request-Id, 12345 nacos: discovery: server-addr: localhost:8848 password: nacos username: nacos sentinel: eager: true transport: dashboard: localhost:8080
启动类中添加注解:前端
@EnableDiscoveryClient @SpringBootApplication public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } }
启动测试,在这里可能会遇到版本冲突的问题:可使用ctrl+alt+shift+u ,而后出现以下图所示,红色就是就是证实存在jar包冲突java
路由:网关的基本构建组成,它由ID,目标URI,谓词集合和过滤器集合定义,若是集合谓词为true,则匹配路由,不然不匹配;web
谓词:这是Java 8函数谓词,输入类型是Spring Framework ServerWebExchange,能够匹配HTTP请求中的全部内容,例如请求头或参数;正则表达式
过滤器:这些是使用特定工厂构造的Spring Framework GatewayFilter实例,能够在发送给下游请求以前或以后修改请求和响应;spring
下图从整体上概述了Spring Cloud Gateway的工做方式:json
客户端向Spring Cloud Gateway发出请求,若是网关处理程序映射肯定请求与路由匹配,则将其发送到网关Web处理程序,该处理程序经过特定于请求的过滤器链运行请求,筛选器由虚线分隔的缘由是,筛选器能够在发送代理请求以前和以后运行逻辑,全部“前置”过滤器逻辑均被执行,而后发出代理请求,发出代理请求后,将运行“后”过滤器逻辑;在没有端口的路由中定义URI,HTTP和HTTPS URI的默认端口值分别是80和443后端
Spring Cloud Gateway将路由匹配做为Spring WebFlux HandlerMapping基础架构的一部分,Spring Cloud Gateway包括许多内置的路由谓词工厂,全部这些谓词都与HTTP请求的不一样属性匹配,能够将多个路由谓词工厂结合使用;跨域
总共有11个路由谓词工厂:
\1. The After Route Predicate Factory
\2. The Before Route Predicate Factory
\3. The Between Route Predicate Factory
\4. The Cookie Route Predicate Factory
\5. The Header Route Predicate Factory
\6. The Host Route Predicate Factory
\7. The Method Route Predicate Factory
\8. The Path Route Predicate Factory
\9. The Query Route Predicate Factory
\10. The RemoteAddr Route Predicate Factory
\11. The Weight Route Predicate Factory
After route谓词工厂采用一个参数,即datetime(这是一个Java ZonedDateTime),该谓词匹配在指定日期时间以后发生的请求,如下示例配置了路由后谓词:
这条路由符合2017年1月20日17:42:47时间([America/Denver])以后的任何请求;
时间经过获取:System.out.println(ZonedDateTime.now());
Before路由谓词工厂采用一个参数,即datetime(这是一个Java ZonedDateTime),该谓词匹配在指定日期时间以前发生的请求,下面的示例配置路由以前谓词:
这条路由符合2017年1月20日17:42:47时间([America/Denver])以前的任何请求;
路由谓词之间的工厂使用两个参数datetime1和datetime2,它们是java ZonedDateTime对象,该谓词匹配在datetime1以后和datetime2以前发生的请求,datetime2参数必须在datetime1以后,如下示例配置了路由之间的谓词:
该路线与2017年1月20日山区时间(丹佛)以后和2017年1月21日17:42山区时间(丹佛)以前的任何请求相匹配,这对于维护时段可能颇有用;
Cookie路由谓词工厂采用两个参数,即cookie名称和一个regexp(这是Java正则表达式),该谓词匹配具备给定名称且其值与正则表达式匹配的cookie,如下示例配置Cookie路由谓词工厂:
此路由匹配具备名为Chocolate的cookie的请求,该cookie的值与ch.p正则表达式匹配;
举例:curl http://192.168.0.104/index --cookie token=123456
header 路由谓词工厂使用两个参数,header 名称和一个regexp(这是Java正则表达式),该谓词与具备给定名称的header 匹配,该header 的值与正则表达式匹配,如下示例配置标头路由谓词:
若是请求具备名为X-Request-Id的标头,且其值与\ d +正则表达式匹配(即,其值为一个或多个数字),则此路由匹配;
举例:curl http://192.168.0.104/index --header "X-Request-Id:19228"
host路由谓词工厂使用一个参数:主机名模式列表,如下示例配置主机路由谓词:
还支持URI模板变量(例如{sub} .myhost.org),若是请求的主机标头的值为www.somehost.org或beta.somehost.org或www.anotherhost.org,则此路由匹配;
方法路由谓词工厂使用方法参数,该参数是一个或多个参数:要匹配的HTTP方法,如下示例配置方法route谓词:
若是请求方法是GET或POST,则此路由匹配;
路径路由谓词工厂使用两个参数:Spring PathMatcher模式列表和一个称为matchOptionalTrailingSeparator的可选标志,如下示例配置路径路由谓词:
若是请求路径为例如/red/1或/red/blue或/blue/green,则此路由匹配;
查询路由谓词工厂采用两个参数:必需的参数和可选的regexp(这是Java正则表达式),如下示例配置查询路由谓词:
若是请求包含green查询参数,则前面的路由匹配;
若是请求包含值与gree匹配的red查询参数,则上述路由匹配;
RemoteAddr路由谓词工厂使用源列表(最小大小为1),这些源是标记(IPv4或IPv6)字符串,例如192.168.0.1/16(其中192.168.0.1是IP地址,而16是子网掩码)),下面的示例配置RemoteAddr路由谓词:
若是请求的远程地址是例如192.168.1.10,则此路由匹配;
权重路由谓词工厂采用两个参数:group和weight(一个int),权重是按组计算的,如下示例配置权重路由谓词:
这条路由会将约80%的流量转发至weight_high.org,并将约20%的流量转发至weight_low.org;
路由过滤器容许以某种方式修改传入的HTTP请求或传出的HTTP响应,Spring Cloud Gateway包括许多内置的GatewayFilter工厂;
总共有31个GatewayFilter工厂:
\1. The AddRequestHeader GatewayFilter Factory
\2. The AddRequestParameter GatewayFilter Factory
\3. The AddResponseHeader GatewayFilter Factory
\4. The DedupeResponseHeader GatewayFilter Factory
\5. The Hystrix GatewayFilter Factory
\6. Spring Cloud CircuitBreaker GatewayFilter Factory
\7. The FallbackHeaders GatewayFilter Factory
\8. The MapRequestHeader GatewayFilter Factory
\9. The PrefixPath GatewayFilter Factory
\10. The PreserveHostHeader GatewayFilter Factory
\11. The RequestRateLimiter GatewayFilter Factory
\12. The RedirectTo GatewayFilter Factory
\13. The RemoveRequestHeader GatewayFilter Factory
\14. RemoveResponseHeader GatewayFilter Factory
\15. The RemoveRequestParameter GatewayFilter Factory
\16. The RewritePath GatewayFilter Factory
\17. RewriteLocationResponseHeader GatewayFilter Factory
\18. The RewriteResponseHeader GatewayFilter Factory
\19. The SaveSession GatewayFilter Factory
\20. The SecureHeaders GatewayFilter Factory
\21. The SetPath GatewayFilter Factory
\22. The SetRequestHeader GatewayFilter Factory
\23. The SetResponseHeader GatewayFilter Factory
\24. The SetStatus GatewayFilter Factory
\25. The StripPrefix GatewayFilter Factory
\26. The Retry GatewayFilter Factory
\27. The RequestSize GatewayFilter Factory
\28. The SetRequestHost GatewayFilter Factory
\29. Modify a Request Body GatewayFilter Factory
\30. Modify a Response Body GatewayFilter Factory
\31. Default Filters
Spring Cloud Gateway内置了一系列的路由谓词工厂,可是若是这些内置的路由谓词工厂不能知足业务需求的话,能够自定义路由谓词工厂来实现特定的需求;
下面列举两个例子:
一、要求请求必须携带一个token,而且token值等于指定的值,才能访问;
二、要求某个服务的用户只容许在23:00 - 6:00这个时间段内才能够访问;
自定义谓词具体步骤:
(1)首先定义一个配置类,用于承载配置参数;
(2)定义一个路由谓词工厂;
注:TokenRoutePredicateFactory类,前面的Token与.yml配置文件里面配置的名字对应,后面的RoutePredicateFactory名字是固定的,不能随便写,这是Spring Cloud Gateway的约定,类名须为“谓词工厂名(好比:Token)” + RoutePredicateFactory
(3)在配置文件中启用该路由谓词工厂,即配置一个Token=123456;
时间格式不是随便配置,而是Spring Cloud Gateway的默认时间格式,采用JDK8里面的格式化:
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.*ofLocalizedTime*(FormatStyle.*SHORT*); String nowTime = dateTimeFormatter.format(ZonedDateTime.*now*()); System.*out*.println(nowTime);
到此为止就实现了一个自定义路由谓词工厂,若此时token值不相等,不在容许的访问时间段内,访问就会报404;
以Token为例:
配置类:
@Data //lombok public class TokenConfig { //获取的是配置文件中设置的token private String token; }
自定义路由谓词工厂:
@Slf4j @Component public class TokenRoutePredicateFactory extends AbstractRoutePredicateFactory<TokenConfig> { public TokenRoutePredicateFactory() { super(TokenConfig.class); } @Override public List<String> shortcutFieldOrder() { return Collections.singletonList("token"); } @Override public Predicate<ServerWebExchange> apply(TokenConfig tokenConfig) { // (T t) -> true return exchange -> { MultiValueMap<String, String> valueMap = exchange.getRequest().getQueryParams();//获取请求中的token字段的值 boolean flag = false; List<String> list = new ArrayList<>(); valueMap.forEach((k, v) -> { list.addAll(v); }); for (String s : list) { log.info("Token -> {} ", s); if (StringUtils.equalsIgnoreCase(s, tokenConfig.getToken())) { flag = true; break; } } return flag; }; } }
若是谓词不匹配时,处理返回404页面显然不合规范。须要咱们对404进行处理
处理的顶层接口是WebExceptionHandler
默认实现是DefaultErrorWebExceptionHandler
咱们须要覆盖它的默认实现DefaultErrorWebExceptionHandler,覆盖里面的方法getRoutingFunction,getHttpStatus,在方法里面编写咱们想要返回的结果
实现类:
public class MyErrorWebExceptionHandler extends DefaultErrorWebExceptionHandler { public MyErrorWebExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties, ErrorProperties errorProperties, ApplicationContext applicationContext) { super(errorAttributes, resourceProperties, errorProperties, applicationContext); } /** * 获取异常属性 */ /*@Override protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) { int code = 500; Throwable error = super.getError(request); if (error instanceof org.springframework.cloud.gateway.support.NotFoundException) { code = 404; } return response(code, this.buildMessage(request, error)); }*/ /** * 指定响应处理方法为JSON处理的方法 * * @param errorAttributes */ @Override protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) { return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse); } /** * 根据code获取对应的HttpStatus * @param errorAttributes */ @Override protected int getHttpStatus(Map<String, Object> errorAttributes) { int statusCode = (int) errorAttributes.get("status"); return statusCode; } /** * 构建异常信息 * @param request * @param ex * @return */ private String buildMessage(ServerRequest request, Throwable ex) { StringBuilder message = new StringBuilder("Failed to handle request ["); message.append(request.methodName()); message.append(" "); message.append(request.uri()); message.append("]"); if (ex != null) { message.append(": "); message.append(ex.getMessage()); } return message.toString(); } /** * 构建返回的JSON数据格式 * * @param status 状态码 * @param errorMessage 异常信息 * @return */ public static Map<String, Object> response(int status, String errorMessage) { Map<String, Object> map = new HashMap<>(); map.put("code", status); map.put("message", errorMessage); map.put("data", null); return map; } }
除此以外,还须要写一个配置类,添加相关配置,使得404时,将相关信息给到上面编写的处理异常类中,并将该异常类返回。
@Configuration public class GatewayConfiguration { private final ServerProperties serverProperties; private final ApplicationContext applicationContext; private final ResourceProperties resourceProperties; private final List<ViewResolver> viewResolvers; private final ServerCodecConfigurer serverCodecConfigurer; //构造函数 public GatewayConfiguration(ServerProperties serverProperties, ApplicationContext applicationContext, ResourceProperties resourceProperties, ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer) { //spring会将这些值从容器中获取到 this.serverProperties = serverProperties; this.applicationContext = applicationContext; this.resourceProperties = resourceProperties; this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList); this.serverCodecConfigurer = serverCodecConfigurer; } @Bean("myErrorWebExceptionHandler") @Order(Ordered.HIGHEST_PRECEDENCE) public ErrorWebExceptionHandler myErrorWebExceptionHandler(ErrorAttributes errorAttributes) { MyErrorWebExceptionHandler exceptionHandler = new MyErrorWebExceptionHandler( errorAttributes, this.resourceProperties, this.serverProperties.getError(), this.applicationContext); exceptionHandler.setViewResolvers(this.viewResolvers); exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters()); exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders()); return exceptionHandler; } }
网关过滤器的顶层接口是GatewayFilterFactory。一般状况下能够继承AbstractGatewayFilterFactory实现自定义网关过滤器;或者继承AbstractNameValueGatewayFilterFactory,该方式配置方式更简单,而后覆盖里面的一个方法apply
/** * 自定义filter */ @Slf4j @Component //类名中FilterFactory固定不可更改成规约 public class RequestLogGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory { @Override public GatewayFilter apply(NameValueConfig config) { return (ServerWebExchange exchange, GatewayFilterChain chain) -> { log.info("请求网关,{}, {}", config.getName(), config.getValue()); MultiValueMap<String, String> valueMap = exchange.getRequest().getQueryParams(); valueMap.forEach((k, v) -> { log.info("请求参数 {} ", k); v.forEach(s -> { log.info("请求参数值 = {} ", s); }); }); return chain.filter(exchange); }; } }
上面的过滤器工厂是执行在指定路由之上,能够称为路由过滤器(或者局部过滤器),而全局过滤器是做用于全部的路由上,对全部的路由进行过滤;
全局过滤器的顶层接口是GlobalFilter ,和GatewayFilter 有同样的接口定义,只不过GlobalFilter 会做用于全部路由;
全局过滤器有执行顺序问题,经过getOrder()方法的返回值决定执行顺序,数值越小越靠前执行;
Spring cloud gateway默认内置了不少全局过滤器,好比:
\1. Combined Global Filter and GatewayFilter Ordering
\2. Forward Routing Filter
\3. The LoadBalancerClient Filter
\4. The ReactiveLoadBalancerClientFilter
\5. The Netty Routing Filter
\6. The Netty Write Response Filter
\7. The RouteToRequestUrl Filter
\8. The Websocket Routing Filter
\9. The Gateway Metrics Filter
\10. Marking An Exchange As Routed
固然咱们也能够自定义全局过滤器
@Slf4j @Component public class CustomGlobalFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { log.info("全局Filter请求......"); MultiValueMap<String, String> valueMap = exchange.getRequest().getQueryParams(); valueMap.forEach((k, v) -> { log.info("全局Filter拦截参数 {} ", k); v.forEach(s -> { log.info("全局Filter拦截参数值 = {} ", s); }); }); return chain.filter(exchange); } @Override public int getOrder() { return 0;//越小越先执行 } }
一经实现,就生效。只要知足实现要求,就实现全局过滤。
实现原理是在全局LoadBalancerClientFilter中进行拦截,而后再该过滤器中依赖LoadBalancerClient loadBalancer,而此负载均衡接口的具体实现是RibbonLoadBalancerClient,即spring cloud gateway已经整合好了ribbon,已经能够实现负载均衡,咱们不须要作任何工做,网关对后端微服务的转发就已经具备负载均衡功能;
网关集成Sentinel是为了流控熔断降级,具体集成整合步骤以下:
一、添加依赖;
*
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId> <version>1.7.2</version> </dependency>
二、在gateway配置文件中添加sentinel控制台配置;
spring: cloud: sentinel: eager: true transport: dashboard: localhost:8080
三、写代码,在spring容器中配置一个Sentinel的全局过滤器;
@Bean @Order(-1) public GlobalFilter sentinelGatewayFilter() { return new SentinelGatewayFilter(); }
四、能够进行测试;
在Gateway的配置类(GatewayConfiguration)中,注入一个实例限流时返回BlockRequestHandler
@Bean @Order(Ordered.HIGHEST_PRECEDENCE) public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler(BlockRequestHandler myBlockRequestHandler) { // Register the block exception handler for Spring Cloud Gateway. //重定向bloack处理 GatewayCallbackManager.setBlockHandler(new RedirectBlockRequestHandler("http://www.baidu.com")); //自定义bloack处理 //GatewayCallbackManager.setBlockHandler((com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler) myBlockRequestHandler); return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer); } /** * 自定义的BlockRequestHandler * * @return */ @Bean(name = "myBlockRequestHandler") public BlockRequestHandler myBlockRequestHandler() { BlockRequestHandler blockRequestHandler = new BlockRequestHandler() { @Override public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) { return ServerResponse.status(HttpStatus.BAD_GATEWAY) .contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue("服务器太热了,它罢工了~" + throwable.getClass())); } }; return blockRequestHandler; }
(1)配置依赖;
*
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-extension</artifactId> </dependency>
(2)暂时不须要配置;
(3)写代码;
/** * 规则持久化 */ public class FileDataSourceInit implements InitFunc { @Override public void init() throws Exception { //能够根据须要指定规则文件的位置 //String ruleDir = System.getProperty("user.home") + "/gateway/rules"; String ruleDir = "E:\\software\\JAVA\\springcloud-alibaba\\package\\Sentinel-dashboard"; String flowRulePath = ruleDir + "/flow-rule.json"; String degradeRulePath = ruleDir + "/degrade-rule.json"; String paramFlowRulePath = ruleDir + "/param-flow-rule.json"; String systemRulePath = ruleDir + "/system-rule.json"; String authorityRulePath = ruleDir + "/authority-rule.json"; this.mkdirIfNotExits(ruleDir); this.createFileIfNotExits(flowRulePath); this.createFileIfNotExits(degradeRulePath); this.createFileIfNotExits(paramFlowRulePath); this.createFileIfNotExits(systemRulePath); this.createFileIfNotExits(authorityRulePath); // 流控规则:可读数据源 ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new FileRefreshableDataSource<>( flowRulePath, flowRuleListParser ); // 将可读数据源注册至FlowRuleManager // 这样当规则文件发生变化时,就会更新规则到内存 FlowRuleManager.register2Property(flowRuleRDS.getProperty()); // 流控规则:可写数据源 WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<>( flowRulePath, this::encodeJson ); // 将可写数据源注册至transport模块的WritableDataSourceRegistry中 // 这样收到控制台推送的规则时,Sentinel会先更新到内存,而后将规则写入到文件中 WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS); // 降级规则:可读数据源 ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = new FileRefreshableDataSource<>( degradeRulePath, degradeRuleListParser ); DegradeRuleManager.register2Property(degradeRuleRDS.getProperty()); // 降级规则:可写数据源 WritableDataSource<List<DegradeRule>> degradeRuleWDS = new FileWritableDataSource<>( degradeRulePath, this::encodeJson ); WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS); // 热点参数规则:可读数据源 ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = new FileRefreshableDataSource<>( paramFlowRulePath, paramFlowRuleListParser ); ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty()); // 热点参数规则:可写数据源 WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>( paramFlowRulePath, this::encodeJson ); ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS); // 系统规则:可读数据源 ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new FileRefreshableDataSource<>( systemRulePath, systemRuleListParser ); SystemRuleManager.register2Property(systemRuleRDS.getProperty()); // 系统规则:可写数据源 WritableDataSource<List<SystemRule>> systemRuleWDS = new FileWritableDataSource<>( systemRulePath, this::encodeJson ); WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS); // 受权规则:可读数据源 ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new FileRefreshableDataSource<>( authorityRulePath, authorityRuleListParser ); AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty()); // 受权规则:可写数据源 WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>( authorityRulePath, this::encodeJson ); WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS); } private Converter<String, List<FlowRule>> flowRuleListParser = source -> JSON.parseObject( source, new TypeReference<List<FlowRule>>() { } ); private Converter<String, List<DegradeRule>> degradeRuleListParser = source -> JSON.parseObject( source, new TypeReference<List<DegradeRule>>() { } ); private Converter<String, List<SystemRule>> systemRuleListParser = source -> JSON.parseObject( source, new TypeReference<List<SystemRule>>() { } ); private Converter<String, List<AuthorityRule>> authorityRuleListParser = source -> JSON.parseObject( source, new TypeReference<List<AuthorityRule>>() { } ); private Converter<String, List<ParamFlowRule>> paramFlowRuleListParser = source -> JSON.parseObject( source, new TypeReference<List<ParamFlowRule>>() { } ); private void mkdirIfNotExits(String filePath) throws IOException { File file = new File(filePath); if (!file.exists()) { file.mkdirs(); } } private void createFileIfNotExits(String filePath) throws IOException { File file = new File(filePath); if (!file.exists()) { file.createNewFile(); } } private <T> String encodeJson(T t) { return JSON.toJSONString(t); } }
(4)配置SPI;
resources\META-INF\services\com.alibaba.csp.sentinel.init.InitFunc
放入第三步类的路径(copy reference)
一、添加sentinel-datasource-nacos依赖;
*
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency>
二、application.properties配置持久化数据源;
spring: cloud: sentinel: eager: true transport: dashboard: localhost:8080 datasource: #ncs1 为配置Map中的key键,随便取 ncs1: nacos: server-addr: locahost:8848 data-id: ${spring.application.name}.json group-id: DEFAULT_GROUP rule-type: flow data-type: json
三、在nacos配置中心配置流控规则(每一个route均可以配置逗号隔开):
[ { "resource": "abc", "controlBehavior": 0, "count": 1.0, "grade": 1, "limitApp": "default", "strategy": 0 } ]
(1)根据自动装配spring-cloud-gateway-core.jar的spring.factories;
(2)GatewayClassPathWarningAutoConfiguration检查前端控制器;
(3)网关自动配置GatewayAutoConfiguration;
(4)RoutePredicateHandlerMapping.getHandlerInternal(...)获取Route;
(5)执行FilteringWebHandler
咱们知道,传统的Ajax请求只能获取在同一个域名下的资源,可是HTML5规范中打破了这种限制,容许Ajax发起跨域的请求;(只是须要设置一下)
其实浏览器自己是能够发起跨域请求的,好比你能够连接一个另外一个域名下的图片或者js,好比,可是javascript脚本是不能获取这些另外一个域名下的资源内容的;
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing),它容许浏览器向跨域的另外一台服务器发出XMLHttpRequest请求,从而克服了AJAX只能访问同域名下的资源的限制;
这种CORS使用了一个额外的HTTP响应头来赋予当前user-agent(浏览器)得到跨域资源的权限,这里的跨域也就是Cross-Origin的概念,这里的权限就是访问另外一个域名下的资源权限;
CORS是如今HTML5标准中的一部分,在大部分现代浏览器中都有所支持,可能在某些老版本的浏览器不支持CORS,若是要兼容一些老的浏览器版本,则须要采用JSONP进行跨域请求;
若是 访问协议、端口(若是指定了端口的话)、host都相同,则称之为同源(不跨域),不然为非同源(跨域)
好比源连接: http://store.company.com/dir/page.html
Spring Cloud Gateway解决跨域问题,只须要配置以下代码便可:
*/**** \* *** *配置网关跨域**cors**请求支持** \* **/** *@Configuration public class CorsConfig { @Bean public CorsWebFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.addAllowedMethod("*");//是什么请求方法(POST,GET) config.addAllowedOrigin("*");//来自哪一个域名的请求,*表明全部 config.addAllowedHeader("*");//是什么请求头 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser()); source.registerCorsConfiguration("/**", config); return new CorsWebFilter(source); } }