init
This commit is contained in:
147
sentinel/sentinel-adapter/sentinel-zuul-adapter/README.md
Normal file
147
sentinel/sentinel-adapter/sentinel-zuul-adapter/README.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# Sentinel Zuul Adapter
|
||||
|
||||
Sentinel Zuul Adapter provides **route level** and **customized API level**
|
||||
flow control for Zuul API Gateway.
|
||||
|
||||
> *Note*: this adapter only support Zuul 1.x.
|
||||
|
||||
## How to use
|
||||
|
||||
1. Add Maven dependency to your `pom.xml`:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-zuul-adapter</artifactId>
|
||||
<version>x.y.z</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
2. Register filters
|
||||
|
||||
For Spring Cloud Zuul users, we only need to inject the three filters in Spring configuration class like this:
|
||||
|
||||
```java
|
||||
@Configuration
|
||||
public class ZuulConfig {
|
||||
|
||||
@Bean
|
||||
public ZuulFilter sentinelZuulPreFilter() {
|
||||
// We can provider the filter order here.
|
||||
return new SentinelZuulPreFilter(10000);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ZuulFilter sentinelZuulPostFilter() {
|
||||
return new SentinelZuulPostFilter(1000);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ZuulFilter sentinelZuulErrorFilter() {
|
||||
return new SentinelZuulErrorFilter(-1);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For original Zuul users:
|
||||
|
||||
```java
|
||||
// Get filter registry
|
||||
final FilterRegistry r = FilterRegistry.instance();
|
||||
|
||||
// We need to register all three filters.
|
||||
SentinelZuulPreFilter sentinelPreFilter = new SentinelZuulPreFilter();
|
||||
r.put("sentinelZuulPreFilter", sentinelPreFilter);
|
||||
SentinelZuulPostFilter postFilter = new SentinelZuulPostFilter();
|
||||
r.put("sentinelZuulPostFilter", postFilter);
|
||||
SentinelZuulErrorFilter errorFilter = new SentinelZuulErrorFilter();
|
||||
r.put("sentinelZuulErrorFilter", errorFilter);
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
As Zuul run as per thread per connection block model, we add filters around route filter to trace Sentinel statistics.
|
||||
|
||||
- `SentinelZuulPreFilter`: This pre-filter will regard all proxy ID (`proxy` in `RequestContext`) and all customized API as resources. When a `BlockException` caught, the filter will try to find a fallback to execute.
|
||||
- `SentinelZuulPostFilter`: When the response has no exception caught, the post filter will complete the entries.
|
||||
- `SentinelZuulErrorFilter`: When an exception is caught, the filter will trace the exception and complete the entries.
|
||||
|
||||
<img width="792" src="https://user-images.githubusercontent.com/9305625/47277113-6b5da780-d5ef-11e8-8a0a-93a6b09b0887.png">
|
||||
|
||||
The order of filters can be changed via the constructor.
|
||||
|
||||
The invocation chain resembles this:
|
||||
|
||||
```bash
|
||||
-EntranceNode: sentinel_gateway_context$$route$$another-route-b(t:0 pq:0.0 bq:0.0 tq:0.0 rt:0.0 prq:0.0 1mp:8 1mb:1 1mt:9)
|
||||
--another-route-b(t:0 pq:0.0 bq:0.0 tq:0.0 rt:0.0 prq:0.0 1mp:4 1mb:1 1mt:5)
|
||||
--another_customized_api(t:0 pq:0.0 bq:0.0 tq:0.0 rt:0.0 prq:0.0 1mp:4 1mb:0 1mt:4)
|
||||
-EntranceNode: sentinel_gateway_context$$route$$my-route-1(t:0 pq:0.0 bq:0.0 tq:0.0 rt:0.0 prq:0.0 1mp:6 1mb:0 1mt:6)
|
||||
--my-route-1(t:0 pq:0.0 bq:0.0 tq:0.0 rt:0.0 prq:0.0 1mp:2 1mb:0 1mt:2)
|
||||
--some_customized_api(t:0 pq:0.0 bq:0.0 tq:0.0 rt:0.0 prq:0.0 1mp:2 1mb:0 1mt:2)
|
||||
```
|
||||
|
||||
## Integration with Sentinel Dashboard
|
||||
|
||||
1. Start [Sentinel Dashboard](https://github.com/alibaba/Sentinel/wiki/Dashboard).
|
||||
2. You can configure the rules in Sentinel dashboard or via dynamic rule configuration.
|
||||
|
||||
## Fallbacks
|
||||
|
||||
You can implement `SentinelFallbackProvider` to define your own fallback provider when Sentinel `BlockException` is thrown.
|
||||
The default fallback provider is `DefaultBlockFallbackProvider`.
|
||||
|
||||
By default fallback route is proxy ID (or customized API name).
|
||||
|
||||
Here is an example:
|
||||
|
||||
```java
|
||||
|
||||
// custom provider
|
||||
public class MyBlockFallbackProvider implements ZuulBlockFallbackProvider {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(DefaultBlockFallbackProvider.class);
|
||||
|
||||
// you can define root as service level
|
||||
@Override
|
||||
public String getRoute() {
|
||||
return "my-route";
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockResponse fallbackResponse(String route, Throwable cause) {
|
||||
RecordLog.info(String.format("[Sentinel DefaultBlockFallbackProvider] Run fallback route: %s", route));
|
||||
if (cause instanceof BlockException) {
|
||||
return new BlockResponse(429, "Sentinel block exception", route);
|
||||
} else {
|
||||
return new BlockResponse(500, "System Error", route);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// register fallback
|
||||
ZuulBlockFallbackManager.registerProvider(new MyBlockFallbackProvider());
|
||||
```
|
||||
|
||||
Default block response:
|
||||
|
||||
```json
|
||||
{
|
||||
"code":429,
|
||||
"message":"Sentinel block exception",
|
||||
"route":"/"
|
||||
}
|
||||
```
|
||||
|
||||
## Request origin parser
|
||||
|
||||
You can register customized request origin parser like this:
|
||||
|
||||
```java
|
||||
public class MyRequestOriginParser implements RequestOriginParser {
|
||||
@Override
|
||||
public String parseOrigin(HttpServletRequest request) {
|
||||
return request.getRemoteAddr();
|
||||
}
|
||||
}
|
||||
```
|
||||
80
sentinel/sentinel-adapter/sentinel-zuul-adapter/pom.xml
Normal file
80
sentinel/sentinel-adapter/sentinel-zuul-adapter/pom.xml
Normal file
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>sentinel-adapter</artifactId>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<version>1.8.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>sentinel-zuul-adapter</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<zuul.version>1.3.1</zuul.version>
|
||||
<servlet.api.version>3.1.0</servlet.api.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-api-gateway-adapter-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>${servlet.api.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.zuul</groupId>
|
||||
<artifactId>zuul-core</artifactId>
|
||||
<version>${zuul.version}</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- we need to use AntPathMatcher in spring-core -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>4.3.20.RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
|
||||
<version>1.4.6.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>4.3.20.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.param.RequestItemParser;
|
||||
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.6.0
|
||||
*/
|
||||
public class RequestContextItemParser implements RequestItemParser<RequestContext> {
|
||||
|
||||
@Override
|
||||
public String getPath(RequestContext requestContext) {
|
||||
return requestContext.getRequest().getServletPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRemoteAddress(RequestContext requestContext) {
|
||||
return requestContext.getRequest().getRemoteAddr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHeader(RequestContext requestContext, String headerKey) {
|
||||
return requestContext.getRequest().getHeader(headerKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUrlParam(RequestContext requestContext, String paramName) {
|
||||
return requestContext.getRequest().getParameter(paramName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCookieValue(RequestContext requestContext, String cookieName) {
|
||||
Cookie[] cookies = requestContext.getRequest().getCookies();
|
||||
if (cookies == null || cookieName == null) {
|
||||
return null;
|
||||
}
|
||||
for (Cookie cookie : cookies) {
|
||||
if (cookie != null && cookieName.equals(cookie.getName())) {
|
||||
return cookie.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.api;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinitionChangeObserver;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.6.0
|
||||
*/
|
||||
public class ZuulApiDefinitionChangeObserver implements ApiDefinitionChangeObserver {
|
||||
|
||||
@Override
|
||||
public void onChange(Set<ApiDefinition> apiDefinitions) {
|
||||
ZuulGatewayApiMatcherManager.loadApiDefinitions(apiDefinitions);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.api;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.zuul.api.matcher.RequestContextApiMatcher;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.6.0
|
||||
*/
|
||||
public final class ZuulGatewayApiMatcherManager {
|
||||
|
||||
private static final Map<String, RequestContextApiMatcher> API_MATCHER_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
public static Map<String, RequestContextApiMatcher> getApiMatcherMap() {
|
||||
return Collections.unmodifiableMap(API_MATCHER_MAP);
|
||||
}
|
||||
|
||||
public static RequestContextApiMatcher getMatcher(final String apiName) {
|
||||
if (apiName == null) {
|
||||
return null;
|
||||
}
|
||||
return API_MATCHER_MAP.get(apiName);
|
||||
}
|
||||
|
||||
public static Set<ApiDefinition> getApiDefinitionSet() {
|
||||
Set<ApiDefinition> set = new HashSet<>();
|
||||
for (RequestContextApiMatcher matcher : API_MATCHER_MAP.values()) {
|
||||
set.add(matcher.getApiDefinition());
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
static synchronized void loadApiDefinitions(/*@Valid*/ Set<ApiDefinition> definitions) {
|
||||
if (definitions == null || definitions.isEmpty()) {
|
||||
API_MATCHER_MAP.clear();
|
||||
return;
|
||||
}
|
||||
for (ApiDefinition definition : definitions) {
|
||||
addApiDefinition(definition);
|
||||
}
|
||||
}
|
||||
|
||||
static void addApiDefinition(ApiDefinition definition) {
|
||||
API_MATCHER_MAP.put(definition.getApiName(), new RequestContextApiMatcher(definition));
|
||||
}
|
||||
|
||||
private ZuulGatewayApiMatcherManager() {}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.api.matcher;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.api.matcher.AbstractApiMatcher;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.zuul.api.route.ZuulRouteMatchers;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
import com.alibaba.csp.sentinel.util.function.Predicate;
|
||||
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.6.0
|
||||
*/
|
||||
public class RequestContextApiMatcher extends AbstractApiMatcher<RequestContext> {
|
||||
|
||||
public RequestContextApiMatcher(ApiDefinition apiDefinition) {
|
||||
super(apiDefinition);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeMatchers() {
|
||||
if (apiDefinition.getPredicateItems() != null) {
|
||||
for (ApiPredicateItem item : apiDefinition.getPredicateItems()) {
|
||||
Predicate<RequestContext> predicate = fromApiPredicate(item);
|
||||
if (predicate != null) {
|
||||
matchers.add(predicate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Predicate<RequestContext> fromApiPredicate(/*@NonNull*/ ApiPredicateItem item) {
|
||||
if (item instanceof ApiPathPredicateItem) {
|
||||
return fromApiPathPredicate((ApiPathPredicateItem)item);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Predicate<RequestContext> fromApiPathPredicate(/*@Valid*/ ApiPathPredicateItem item) {
|
||||
String pattern = item.getPattern();
|
||||
if (StringUtil.isBlank(pattern)) {
|
||||
return null;
|
||||
}
|
||||
switch (item.getMatchStrategy()) {
|
||||
case SentinelGatewayConstants.URL_MATCH_STRATEGY_REGEX:
|
||||
return ZuulRouteMatchers.regexPath(pattern);
|
||||
case SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX:
|
||||
return ZuulRouteMatchers.antPath(pattern);
|
||||
default:
|
||||
return ZuulRouteMatchers.exactPath(pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.api.route;
|
||||
|
||||
import com.alibaba.csp.sentinel.util.AssertUtil;
|
||||
import com.alibaba.csp.sentinel.util.function.Predicate;
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.6.0
|
||||
*/
|
||||
public class PrefixRoutePathMatcher implements Predicate<RequestContext> {
|
||||
|
||||
private final String pattern;
|
||||
|
||||
private final PathMatcher pathMatcher;
|
||||
private final boolean canMatch;
|
||||
|
||||
public PrefixRoutePathMatcher(String pattern) {
|
||||
AssertUtil.assertNotBlank(pattern, "pattern cannot be blank");
|
||||
this.pattern = pattern;
|
||||
this.pathMatcher = new AntPathMatcher();
|
||||
this.canMatch = pathMatcher.isPattern(pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(RequestContext context) {
|
||||
//Solve the problem of prefix matching
|
||||
HttpServletRequest request = context.getRequest();
|
||||
String path = request.getRequestURI();
|
||||
if (path == null) {
|
||||
AssertUtil.assertNotBlank(pattern, "requesturi cannot be blank");
|
||||
}
|
||||
if (canMatch) {
|
||||
return pathMatcher.match(pattern, path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.api.route;
|
||||
|
||||
import com.alibaba.csp.sentinel.util.AssertUtil;
|
||||
import com.alibaba.csp.sentinel.util.function.Predicate;
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.6.0
|
||||
*/
|
||||
public class RegexRoutePathMatcher implements Predicate<RequestContext> {
|
||||
|
||||
private final String pattern;
|
||||
private final Pattern regex;
|
||||
|
||||
public RegexRoutePathMatcher(String pattern) {
|
||||
AssertUtil.assertNotBlank(pattern, "pattern cannot be blank");
|
||||
this.pattern = pattern;
|
||||
this.regex = Pattern.compile(pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(RequestContext context) {
|
||||
//Solve the problem of route matching
|
||||
HttpServletRequest request = context.getRequest();
|
||||
String path = request.getRequestURI();
|
||||
if (path == null) {
|
||||
AssertUtil.assertNotBlank(pattern, "requesturi cannot be blank");
|
||||
}
|
||||
return regex.matcher(path).matches();
|
||||
}
|
||||
|
||||
public String getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.api.route;
|
||||
|
||||
import com.alibaba.csp.sentinel.util.function.Predicate;
|
||||
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.6.0
|
||||
*/
|
||||
public final class ZuulRouteMatchers {
|
||||
|
||||
public static Predicate<RequestContext> all() {
|
||||
return new Predicate<RequestContext>() {
|
||||
@Override
|
||||
public boolean test(RequestContext requestContext) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Predicate<RequestContext> antPath(String pathPattern) {
|
||||
return new PrefixRoutePathMatcher(pathPattern);
|
||||
}
|
||||
|
||||
public static Predicate<RequestContext> exactPath(final String path) {
|
||||
return new Predicate<RequestContext>() {
|
||||
@Override
|
||||
public boolean test(RequestContext exchange) {
|
||||
return exchange.getRequest().getServletPath().equals(path);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Predicate<RequestContext> regexPath(String pathPattern) {
|
||||
return new RegexRoutePathMatcher(pathPattern);
|
||||
}
|
||||
|
||||
private ZuulRouteMatchers() {}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.callback;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* @author tiger
|
||||
*/
|
||||
public class DefaultRequestOriginParser implements RequestOriginParser {
|
||||
|
||||
@Override
|
||||
public String parseOrigin(HttpServletRequest request) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.callback;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* The origin parser parses request origin (e.g. IP, user, appName) from HTTP request.
|
||||
*
|
||||
* @author tiger
|
||||
*/
|
||||
public interface RequestOriginParser {
|
||||
|
||||
/**
|
||||
* Parse the origin from given HTTP request.
|
||||
*
|
||||
* @param request HTTP request
|
||||
* @return parsed origin
|
||||
*/
|
||||
String parseOrigin(HttpServletRequest request);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.callback;
|
||||
|
||||
import com.alibaba.csp.sentinel.util.AssertUtil;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.6.0
|
||||
*/
|
||||
public final class ZuulGatewayCallbackManager {
|
||||
|
||||
private static volatile RequestOriginParser originParser = new DefaultRequestOriginParser();
|
||||
|
||||
public static RequestOriginParser getOriginParser() {
|
||||
return originParser;
|
||||
}
|
||||
|
||||
public static void setOriginParser(RequestOriginParser originParser) {
|
||||
AssertUtil.notNull(originParser, "originParser cannot be null");
|
||||
ZuulGatewayCallbackManager.originParser = originParser;
|
||||
}
|
||||
|
||||
private ZuulGatewayCallbackManager() {}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.constants;
|
||||
|
||||
import com.netflix.zuul.ZuulFilter;
|
||||
|
||||
/**
|
||||
* @author tiger
|
||||
*/
|
||||
public class ZuulConstant {
|
||||
|
||||
/**
|
||||
* Zuul {@link com.netflix.zuul.context.RequestContext} key for use in load balancer.
|
||||
*/
|
||||
public static final String SERVICE_ID_KEY = "serviceId";
|
||||
/**
|
||||
* Zuul {@link com.netflix.zuul.context.RequestContext} key for proxying (route ID).
|
||||
*/
|
||||
public static final String PROXY_ID_KEY = "proxy";
|
||||
|
||||
/**
|
||||
* {@link ZuulFilter#filterType()} error type.
|
||||
*/
|
||||
public static final String ERROR_TYPE = "error";
|
||||
|
||||
/**
|
||||
* {@link ZuulFilter#filterType()} post type.
|
||||
*/
|
||||
public static final String POST_TYPE = "post";
|
||||
|
||||
/**
|
||||
* {@link ZuulFilter#filterType()} pre type.
|
||||
*/
|
||||
public static final String PRE_TYPE = "pre";
|
||||
|
||||
/**
|
||||
* {@link ZuulFilter#filterType()} route type.
|
||||
*/
|
||||
public static final String ROUTE_TYPE = "route";
|
||||
|
||||
/**
|
||||
* Filter Order for SEND_RESPONSE_FILTER_ORDER
|
||||
*/
|
||||
public static final int SEND_RESPONSE_FILTER_ORDER = 1000;
|
||||
|
||||
/**
|
||||
* Zuul use Sentinel as default context when serviceId is empty.
|
||||
*/
|
||||
public static final String ZUUL_DEFAULT_CONTEXT = "zuul_default_context";
|
||||
|
||||
/**
|
||||
* Zuul context key for keeping Sentinel entries.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*/
|
||||
public static final String ZUUL_CTX_SENTINEL_ENTRIES_KEY = "_sentinel_entries";
|
||||
|
||||
private ZuulConstant(){}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback;
|
||||
|
||||
/**
|
||||
* Fall back response for {@link com.alibaba.csp.sentinel.slots.block.BlockException}
|
||||
*
|
||||
* @author tiger
|
||||
*/
|
||||
public class BlockResponse {
|
||||
|
||||
/**
|
||||
* HTTP status code.
|
||||
*/
|
||||
private int code;
|
||||
|
||||
private String message;
|
||||
private String route;
|
||||
|
||||
public BlockResponse(int code, String message, String route) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.route = route;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getRoute() {
|
||||
return route;
|
||||
}
|
||||
|
||||
public void setRoute(String route) {
|
||||
this.route = route;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{" +
|
||||
"\"code\":" + code +
|
||||
", \"message\":" + "\"" + message + "\"" +
|
||||
", \"route\":" + "\"" + route + "\"" +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
|
||||
/**
|
||||
* Default Fallback provider for sentinel {@link BlockException}, {@literal *} meant for all routes.
|
||||
*
|
||||
* @author tiger
|
||||
*/
|
||||
public class DefaultBlockFallbackProvider implements ZuulBlockFallbackProvider {
|
||||
|
||||
@Override
|
||||
public String getRoute() {
|
||||
return "*";
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockResponse fallbackResponse(String route, Throwable cause) {
|
||||
if (cause instanceof BlockException) {
|
||||
return new BlockResponse(429, "Sentinel block exception", route);
|
||||
} else {
|
||||
return new BlockResponse(500, "System Error", route);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.alibaba.csp.sentinel.util.AssertUtil;
|
||||
|
||||
/**
|
||||
* This provide fall back class manager.
|
||||
*
|
||||
* @author tiger
|
||||
*/
|
||||
public class ZuulBlockFallbackManager {
|
||||
|
||||
private static Map<String, ZuulBlockFallbackProvider> fallbackProviderCache = new HashMap<>();
|
||||
|
||||
private static ZuulBlockFallbackProvider defaultFallbackProvider = new DefaultBlockFallbackProvider();
|
||||
|
||||
/**
|
||||
* Register special provider for different route.
|
||||
*/
|
||||
public static synchronized void registerProvider(ZuulBlockFallbackProvider provider) {
|
||||
AssertUtil.notNull(provider, "fallback provider cannot be null");
|
||||
String route = provider.getRoute();
|
||||
if ("*".equals(route) || route == null) {
|
||||
defaultFallbackProvider = provider;
|
||||
} else {
|
||||
fallbackProviderCache.put(route, provider);
|
||||
}
|
||||
}
|
||||
|
||||
public static ZuulBlockFallbackProvider getFallbackProvider(String route) {
|
||||
ZuulBlockFallbackProvider provider = fallbackProviderCache.get(route);
|
||||
if (provider == null) {
|
||||
provider = defaultFallbackProvider;
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
|
||||
public synchronized static void clear(){
|
||||
fallbackProviderCache.clear();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback;
|
||||
|
||||
/**
|
||||
* This interface is compatible for different spring cloud version.
|
||||
*
|
||||
* @author tiger
|
||||
*/
|
||||
public interface ZuulBlockFallbackProvider {
|
||||
|
||||
/**
|
||||
* The route this fallback will be used for.
|
||||
* @return The route the fallback will be used for.
|
||||
*/
|
||||
String getRoute();
|
||||
|
||||
/**
|
||||
* Provides a fallback response based on the cause of the failed execution.
|
||||
*
|
||||
* @param route The route the fallback is for
|
||||
* @param cause cause of the main method failure, may be <code>null</code>
|
||||
* @return the fallback response
|
||||
*/
|
||||
BlockResponse fallbackResponse(String route, Throwable cause);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.filters;
|
||||
|
||||
import com.alibaba.csp.sentinel.Entry;
|
||||
|
||||
/**
|
||||
* @author wavesZh
|
||||
*/
|
||||
class EntryHolder {
|
||||
|
||||
final private Entry entry;
|
||||
|
||||
final private Object[] params;
|
||||
|
||||
public EntryHolder(Entry entry, Object[] params) {
|
||||
this.entry = entry;
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public Entry getEntry() {
|
||||
return entry;
|
||||
}
|
||||
|
||||
public Object[] getParams() {
|
||||
return params;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.filters;
|
||||
|
||||
import java.util.Deque;
|
||||
|
||||
import com.alibaba.csp.sentinel.Entry;
|
||||
import com.alibaba.csp.sentinel.Tracer;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.zuul.constants.ZuulConstant;
|
||||
import com.alibaba.csp.sentinel.context.ContextUtil;
|
||||
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.6.0
|
||||
*/
|
||||
final class SentinelEntryUtils {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static void tryExitFromCurrentContext() {
|
||||
RequestContext ctx = RequestContext.getCurrentContext();
|
||||
if (ctx.containsKey(ZuulConstant.ZUUL_CTX_SENTINEL_ENTRIES_KEY)) {
|
||||
Deque<EntryHolder> holders = (Deque<EntryHolder>) ctx.get(ZuulConstant.ZUUL_CTX_SENTINEL_ENTRIES_KEY);
|
||||
EntryHolder holder;
|
||||
while (!holders.isEmpty()) {
|
||||
holder = holders.pop();
|
||||
exit(holder);
|
||||
}
|
||||
ctx.remove(ZuulConstant.ZUUL_CTX_SENTINEL_ENTRIES_KEY);
|
||||
}
|
||||
|
||||
ContextUtil.exit();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static void tryTraceExceptionThenExitFromCurrentContext(Throwable t) {
|
||||
RequestContext ctx = RequestContext.getCurrentContext();
|
||||
if (ctx.containsKey(ZuulConstant.ZUUL_CTX_SENTINEL_ENTRIES_KEY)) {
|
||||
Deque<EntryHolder> holders = (Deque<EntryHolder>) ctx.get(ZuulConstant.ZUUL_CTX_SENTINEL_ENTRIES_KEY);
|
||||
EntryHolder holder;
|
||||
while (!holders.isEmpty()) {
|
||||
holder = holders.pop();
|
||||
Tracer.traceEntry(t, holder.getEntry());
|
||||
exit(holder);
|
||||
}
|
||||
ctx.remove(ZuulConstant.ZUUL_CTX_SENTINEL_ENTRIES_KEY);
|
||||
}
|
||||
ContextUtil.exit();
|
||||
}
|
||||
|
||||
static void exit(EntryHolder holder) {
|
||||
Entry entry = holder.getEntry();
|
||||
entry.exit(1, holder.getParams());
|
||||
}
|
||||
|
||||
private SentinelEntryUtils() {}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.filters;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.zuul.constants.ZuulConstant;
|
||||
import com.alibaba.csp.sentinel.log.RecordLog;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
|
||||
import com.netflix.zuul.ZuulFilter;
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
import com.netflix.zuul.exception.ZuulException;
|
||||
|
||||
/**
|
||||
* This filter track routing exception and exit entry;
|
||||
*
|
||||
* @author tiger
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class SentinelZuulErrorFilter extends ZuulFilter {
|
||||
|
||||
private final int order;
|
||||
|
||||
public SentinelZuulErrorFilter() {
|
||||
this(-1);
|
||||
}
|
||||
|
||||
public SentinelZuulErrorFilter(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filterType() {
|
||||
return ZuulConstant.ERROR_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldFilter() {
|
||||
RequestContext ctx = RequestContext.getCurrentContext();
|
||||
return ctx.getThrowable() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int filterOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object run() throws ZuulException {
|
||||
RequestContext ctx = RequestContext.getCurrentContext();
|
||||
Throwable throwable = ctx.getThrowable();
|
||||
if (throwable != null) {
|
||||
if (!BlockException.isBlockException(throwable)) {
|
||||
// Trace exception for each entry and exit entries in order.
|
||||
// The entries can be retrieved from the request context.
|
||||
SentinelEntryUtils.tryTraceExceptionThenExitFromCurrentContext(throwable);
|
||||
RecordLog.info("[SentinelZuulErrorFilter] Trace error cause", throwable.getCause());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.filters;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.zuul.constants.ZuulConstant;
|
||||
|
||||
import com.netflix.zuul.ZuulFilter;
|
||||
import com.netflix.zuul.exception.ZuulException;
|
||||
|
||||
import static com.alibaba.csp.sentinel.adapter.gateway.zuul.constants.ZuulConstant.SEND_RESPONSE_FILTER_ORDER;
|
||||
|
||||
/**
|
||||
* This filter will mark complete and exit {@link com.alibaba.csp.sentinel.Entry}.
|
||||
*
|
||||
* @author tiger
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class SentinelZuulPostFilter extends ZuulFilter {
|
||||
|
||||
private final int order;
|
||||
|
||||
public SentinelZuulPostFilter() {
|
||||
this(SEND_RESPONSE_FILTER_ORDER);
|
||||
}
|
||||
|
||||
public SentinelZuulPostFilter(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filterType() {
|
||||
return ZuulConstant.POST_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int filterOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldFilter() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object run() throws ZuulException {
|
||||
// Exit the entries in order.
|
||||
// The entries can be retrieved from the request context.
|
||||
SentinelEntryUtils.tryExitFromCurrentContext();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.filters;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.alibaba.csp.sentinel.AsyncEntry;
|
||||
import com.alibaba.csp.sentinel.EntryType;
|
||||
import com.alibaba.csp.sentinel.ResourceTypeConstants;
|
||||
import com.alibaba.csp.sentinel.SphU;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.param.GatewayParamParser;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.zuul.RequestContextItemParser;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.zuul.api.ZuulGatewayApiMatcherManager;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.zuul.api.matcher.RequestContextApiMatcher;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.zuul.callback.ZuulGatewayCallbackManager;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.zuul.constants.ZuulConstant;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.BlockResponse;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackManager;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackProvider;
|
||||
import com.alibaba.csp.sentinel.context.ContextUtil;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
import com.alibaba.csp.sentinel.util.function.Predicate;
|
||||
|
||||
import com.netflix.zuul.ZuulFilter;
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
import com.netflix.zuul.exception.ZuulException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import static com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants.*;
|
||||
|
||||
/**
|
||||
* This pre-filter will regard all {@code proxyId} and all customized API as resources.
|
||||
* When a BlockException caught, the filter will try to find a fallback to execute.
|
||||
*
|
||||
* @author tiger
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class SentinelZuulPreFilter extends ZuulFilter {
|
||||
|
||||
private final int order;
|
||||
|
||||
private final GatewayParamParser<RequestContext> paramParser = new GatewayParamParser<>(
|
||||
new RequestContextItemParser());
|
||||
|
||||
public SentinelZuulPreFilter() {
|
||||
this(10000);
|
||||
}
|
||||
|
||||
public SentinelZuulPreFilter(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filterType() {
|
||||
return ZuulConstant.PRE_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* This run before route filter so we can get more accurate RT time.
|
||||
*/
|
||||
@Override
|
||||
public int filterOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldFilter() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void doSentinelEntry(String resourceName, final int resType, RequestContext requestContext,
|
||||
Deque<EntryHolder> holders) throws BlockException {
|
||||
Object[] params = paramParser.parseParameterFor(resourceName, requestContext,
|
||||
new Predicate<GatewayFlowRule>() {
|
||||
@Override
|
||||
public boolean test(GatewayFlowRule r) {
|
||||
return r.getResourceMode() == resType;
|
||||
}
|
||||
});
|
||||
AsyncEntry entry = SphU.asyncEntry(resourceName, ResourceTypeConstants.COMMON_API_GATEWAY,
|
||||
EntryType.IN, params);
|
||||
EntryHolder holder = new EntryHolder(entry, params);
|
||||
holders.push(holder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object run() throws ZuulException {
|
||||
RequestContext ctx = RequestContext.getCurrentContext();
|
||||
String origin = parseOrigin(ctx.getRequest());
|
||||
String routeId = (String)ctx.get(ZuulConstant.PROXY_ID_KEY);
|
||||
|
||||
Deque<EntryHolder> holders = new ArrayDeque<>();
|
||||
String fallBackRoute = routeId;
|
||||
try {
|
||||
if (StringUtil.isNotBlank(routeId)) {
|
||||
ContextUtil.enter(GATEWAY_CONTEXT_ROUTE_PREFIX + routeId, origin);
|
||||
doSentinelEntry(routeId, RESOURCE_MODE_ROUTE_ID, ctx, holders);
|
||||
}
|
||||
|
||||
Set<String> matchingApis = pickMatchingApiDefinitions(ctx);
|
||||
if (!matchingApis.isEmpty() && ContextUtil.getContext() == null) {
|
||||
ContextUtil.enter(ZuulConstant.ZUUL_DEFAULT_CONTEXT, origin);
|
||||
}
|
||||
for (String apiName : matchingApis) {
|
||||
fallBackRoute = apiName;
|
||||
doSentinelEntry(apiName, RESOURCE_MODE_CUSTOM_API_NAME, ctx, holders);
|
||||
}
|
||||
} catch (BlockException ex) {
|
||||
ZuulBlockFallbackProvider zuulBlockFallbackProvider = ZuulBlockFallbackManager.getFallbackProvider(
|
||||
fallBackRoute);
|
||||
BlockResponse blockResponse = zuulBlockFallbackProvider.fallbackResponse(fallBackRoute, ex);
|
||||
// Prevent routing from running
|
||||
ctx.setRouteHost(null);
|
||||
ctx.set(ZuulConstant.SERVICE_ID_KEY, null);
|
||||
|
||||
// Set fallback response.
|
||||
ctx.setResponseBody(blockResponse.toString());
|
||||
ctx.setResponseStatusCode(blockResponse.getCode());
|
||||
// Set Response ContentType
|
||||
ctx.getResponse().setContentType("application/json; charset=utf-8");
|
||||
} finally {
|
||||
// We don't exit the entry here. We need to exit the entries in post filter to record Rt correctly.
|
||||
// So here the entries will be carried in the request context.
|
||||
if (!holders.isEmpty()) {
|
||||
ctx.put(ZuulConstant.ZUUL_CTX_SENTINEL_ENTRIES_KEY, holders);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String parseOrigin(HttpServletRequest request) {
|
||||
return ZuulGatewayCallbackManager.getOriginParser().parseOrigin(request);
|
||||
}
|
||||
|
||||
private Set<String> pickMatchingApiDefinitions(RequestContext requestContext) {
|
||||
Set<String> apis = new HashSet<>();
|
||||
for (RequestContextApiMatcher matcher : ZuulGatewayApiMatcherManager.getApiMatcherMap().values()) {
|
||||
if (matcher.test(requestContext)) {
|
||||
apis.add(matcher.getApiName());
|
||||
}
|
||||
}
|
||||
return apis;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
com.alibaba.csp.sentinel.adapter.gateway.zuul.api.ZuulApiDefinitionChangeObserver
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author tiger
|
||||
*/
|
||||
public class ZuulBlockFallbackManagerTest {
|
||||
|
||||
private String ROUTE = "/test";
|
||||
|
||||
private String DEFAULT_ROUTE = "*";
|
||||
|
||||
class MyNullResponseFallBackProvider implements ZuulBlockFallbackProvider {
|
||||
@Override
|
||||
public String getRoute() {
|
||||
return ROUTE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockResponse fallbackResponse(String route, Throwable cause) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterProvider() throws Exception {
|
||||
MyNullResponseFallBackProvider myNullResponseFallBackProvider = new MyNullResponseFallBackProvider();
|
||||
ZuulBlockFallbackManager.registerProvider(myNullResponseFallBackProvider);
|
||||
Assert.assertEquals(myNullResponseFallBackProvider.getRoute(), ROUTE);
|
||||
Assert.assertNull(myNullResponseFallBackProvider.fallbackResponse(ROUTE, new FlowException("flow ex")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clear() {
|
||||
MyNullResponseFallBackProvider myNullResponseFallBackProvider = new MyNullResponseFallBackProvider();
|
||||
ZuulBlockFallbackManager.registerProvider(myNullResponseFallBackProvider);
|
||||
Assert.assertEquals(myNullResponseFallBackProvider.getRoute(), ROUTE);
|
||||
ZuulBlockFallbackManager.clear();
|
||||
Assert.assertEquals(ZuulBlockFallbackManager.getFallbackProvider(ROUTE).getRoute(), DEFAULT_ROUTE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author tiger
|
||||
*/
|
||||
public class ZuulBlockFallbackProviderTest {
|
||||
|
||||
private String ALL_ROUTE = "*";
|
||||
|
||||
@Test
|
||||
public void testGetNullRoute() throws Exception {
|
||||
ZuulBlockFallbackProvider fallbackProvider = ZuulBlockFallbackManager.getFallbackProvider(null);
|
||||
Assert.assertEquals(fallbackProvider.getRoute(), ALL_ROUTE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDefaultRoute() throws Exception {
|
||||
ZuulBlockFallbackProvider fallbackProvider = ZuulBlockFallbackManager.getFallbackProvider(ALL_ROUTE);
|
||||
Assert.assertEquals(fallbackProvider.getRoute(), ALL_ROUTE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNotInCacheRoute() throws Exception {
|
||||
ZuulBlockFallbackProvider fallbackProvider = ZuulBlockFallbackManager.getFallbackProvider("/not/in");
|
||||
Assert.assertEquals(fallbackProvider.getRoute(), ALL_ROUTE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlowControlFallbackResponse() throws Exception {
|
||||
ZuulBlockFallbackProvider fallbackProvider = ZuulBlockFallbackManager.getFallbackProvider(ALL_ROUTE);
|
||||
BlockResponse clientHttpResponse = fallbackProvider.fallbackResponse(ALL_ROUTE,
|
||||
new FlowException("flow exception"));
|
||||
Assert.assertEquals(clientHttpResponse.getCode(), 429);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRuntimeExceptionFallbackResponse() throws Exception {
|
||||
ZuulBlockFallbackProvider fallbackProvider = ZuulBlockFallbackManager.getFallbackProvider(ALL_ROUTE);
|
||||
BlockResponse clientHttpResponse = fallbackProvider.fallbackResponse(ALL_ROUTE, new RuntimeException());
|
||||
Assert.assertEquals(clientHttpResponse.getCode(), 500);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.filters;
|
||||
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import static com.alibaba.csp.sentinel.adapter.gateway.zuul.constants.ZuulConstant.ERROR_TYPE;
|
||||
|
||||
/**
|
||||
* @author tiger
|
||||
*/
|
||||
public class SentinelZuulErrorFilterTest {
|
||||
|
||||
@Test
|
||||
public void testFilterType() throws Exception {
|
||||
SentinelZuulErrorFilter sentinelZuulErrorFilter = new SentinelZuulErrorFilter();
|
||||
Assert.assertEquals(sentinelZuulErrorFilter.filterType(), ERROR_TYPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldFilter() {
|
||||
SentinelZuulErrorFilter sentinelZuulErrorFilter = new SentinelZuulErrorFilter();
|
||||
RequestContext ctx = RequestContext.getCurrentContext();
|
||||
ctx.setThrowable(new RuntimeException());
|
||||
Assert.assertTrue(sentinelZuulErrorFilter.shouldFilter());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun() throws Exception {
|
||||
SentinelZuulErrorFilter sentinelZuulErrorFilter = new SentinelZuulErrorFilter();
|
||||
Object result = sentinelZuulErrorFilter.run();
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.filters;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import static com.alibaba.csp.sentinel.adapter.gateway.zuul.constants.ZuulConstant.POST_TYPE;
|
||||
|
||||
/**
|
||||
* @author tiger
|
||||
*/
|
||||
public class SentinelZuulPostFilterTest {
|
||||
|
||||
@Test
|
||||
public void testFilterType() throws Exception {
|
||||
SentinelZuulPostFilter sentinelZuulPostFilter = new SentinelZuulPostFilter();
|
||||
Assert.assertEquals(sentinelZuulPostFilter.filterType(), POST_TYPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun() throws Exception {
|
||||
SentinelZuulPostFilter sentinelZuulPostFilter = new SentinelZuulPostFilter();
|
||||
Object result = sentinelZuulPostFilter.run();
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.filters;
|
||||
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import static com.alibaba.csp.sentinel.adapter.gateway.zuul.constants.ZuulConstant.PRE_TYPE;
|
||||
import static com.alibaba.csp.sentinel.adapter.gateway.zuul.constants.ZuulConstant.SERVICE_ID_KEY;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author tiger
|
||||
*/
|
||||
public class SentinelZuulPreFilterTest {
|
||||
|
||||
private String SERVICE_ID = "servicea";
|
||||
|
||||
private String URI = "/servicea/test";
|
||||
|
||||
@Mock
|
||||
private HttpServletRequest httpServletRequest;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(httpServletRequest.getContextPath()).thenReturn("");
|
||||
when(httpServletRequest.getPathInfo()).thenReturn(URI);
|
||||
RequestContext requestContext = new RequestContext();
|
||||
requestContext.set(SERVICE_ID_KEY, SERVICE_ID);
|
||||
requestContext.setRequest(httpServletRequest);
|
||||
RequestContext.testSetCurrentContext(requestContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilterType() throws Exception {
|
||||
SentinelZuulPreFilter sentinelZuulPreFilter = new SentinelZuulPreFilter();
|
||||
Assert.assertEquals(sentinelZuulPreFilter.filterType(), PRE_TYPE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.alibaba.csp.sentinel.adapter.gateway.zuul.route;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.zuul.api.route.PrefixRoutePathMatcher;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.zuul.api.route.RegexRoutePathMatcher;
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
import static com.alibaba.csp.sentinel.adapter.gateway.zuul.constants.ZuulConstant.SERVICE_ID_KEY;
|
||||
|
||||
/**
|
||||
* @author: jiangzian
|
||||
**/
|
||||
public class SentinelZuulRouteTest {
|
||||
|
||||
private final String SERVICE_ID = "servicea";
|
||||
|
||||
private final String SERVER_NAME = "www.example.com";
|
||||
private final String REQUEST_URI = "/servicea/test.jsp";
|
||||
private final String QUERY_STRING = "param1=value1¶m";
|
||||
|
||||
private RequestContext requestContext = new RequestContext();
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServerName(SERVER_NAME);
|
||||
request.setRequestURI(REQUEST_URI);
|
||||
request.setQueryString(QUERY_STRING);
|
||||
requestContext.set(SERVICE_ID_KEY, SERVICE_ID);
|
||||
requestContext.setRequest(request);
|
||||
RequestContext.testSetCurrentContext(requestContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrefixRoutePathMatche() {
|
||||
PrefixRoutePathMatcher prefixRoutePathMatcher = new PrefixRoutePathMatcher("/servicea/????.jsp");
|
||||
Assert.assertTrue(prefixRoutePathMatcher.test(requestContext));
|
||||
|
||||
prefixRoutePathMatcher = new PrefixRoutePathMatcher("/servicea/????.do");
|
||||
Assert.assertTrue(!prefixRoutePathMatcher.test(requestContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegexRoutePathMatcher() {
|
||||
RegexRoutePathMatcher regexRoutePathMatcher = new RegexRoutePathMatcher("/servicea/[a-zA-z]+(\\.jsp)");
|
||||
Assert.assertTrue(regexRoutePathMatcher.test(requestContext));
|
||||
|
||||
regexRoutePathMatcher = new RegexRoutePathMatcher("/serviceb/[a-zA-z]+(\\.jsp)");
|
||||
Assert.assertTrue(!regexRoutePathMatcher.test(requestContext));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user