springcloud-eureka集群-整合zuul网关
pom.xml依赖
<dependencies>
<!-- zuul -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.5</version>
</dependency>
<!-- 监控 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 安全验证 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- 动态加载 -->
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>3.0.0-alpha-1</version>
</dependency>
<!-- Netflix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>
application.yml
server:
port: 9000
spring:
application:
name: tms-zuul
eureka:
instance:
prefer-ip-address: true
lease-renewal-interval-in-seconds: 30
lease-expiration-duration-in-seconds: 90
metadata-map:
name: tms-zuul-metadata-map-name
client:
serviceUrl:
defaultZone: http://admin:[email protected]:8761/eureka/, http://admin:[email protected]:8762/eureka/
# 抓取服务列表时间间隔
registry-fetch-interval-seconds: 30
zuul:
max:
host:
connections: 500
host:
socket-timeout-millis: 60000
connect-timeout-millis: 60000
routes:
tms-service:
path: /tms-service/**
serviceId: tms-service
tms-service-manager:
path: /tms-service-manager/**
serviceId: tms-service-manager
hystrix:
command:
default:
execution:
timeout:
enabled: true
isolation:
thread:
timeoutInMilliseconds: 60000
ribbon:
ReadTimeout: 60000
ConnectTimeout: 60000
MaxAutoRetries: 0
MaxAutoRetriesNextServer: 1
endpoints:
sensitive: false
shutdown:
enabled: true
sensitive: true
security:
user:
name: admin
password: admin
role: SUPERUSER
management:
context-path: /tms-zuul
security:
roles: SUPERUSER #角色
# 日志
logging:
file: logs/logger.log
level:
com.netflix: DEBUG
org.springframework.web: DEBUG
org.springframework.security: INFO
TmsZuulApplication.java
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class TmsZuulApplication {
private final static Logger logger = LoggerFactory.getLogger(TmsZuulApplication.class);
public static void main(String[] args) {
SpringApplication.run(TmsZuulApplication.class, args);
}
/**
* groovy文件路径
*/
@Value("${zuul.filter.root}")
private String scriptRoot;
/**
* 刷新groovy文件间隔时间
*/
@Value("${zuul.filter.refreshInterval}")
private String refreshInterval;
/**
* 动态加载拦截器
*/
@PostConstruct
public void zuulInit(){
FilterLoader.getInstance().setCompiler(new GroovyCompiler());
try {
scriptRoot = scriptRoot + File.separator;
FilterFileManager.setFilenameFilter(new GroovyFileFilter());
FilterFileManager.init(Integer.parseInt(refreshInterval),
scriptRoot + "pre", scriptRoot + "route", scriptRoot + "post");
logger.info("======== zuulInit() 动态加载网关拦截器 ========");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
zuul error回退接口
@Component
public class TmsServiceFallbackProvider implements ZuulFallbackProvider {
private static Logger logger = LoggerFactory.getLogger(TmsServiceFallbackProvider.class);
@Override
public String getRoute() {
return "ZuulFallbackProvider";
}
@Override
public ClientHttpResponse fallbackResponse() {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return this.getStatusCode().value();
}
@Override
public String getStatusText() throws IOException {
return this.getStatusCode().getReasonPhrase();
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
String msg = "Service Unavailable";
logger.info(msg);
return new ByteArrayInputStream(msg.getBytes());
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders httpHeaders = new HttpHeaders();
MediaType mediaType = new MediaType("application", "json", Charset.forName("UTF-8"));
httpHeaders.setContentType(mediaType);
return httpHeaders;
}
};
}
}
自定义拦截器
@Component
public class MyZuulFilter extends ZuulFilter {
private static Logger logger = LoggerFactory.getLogger(MyZuulFilter.class);
/**
* 过滤器类型
* pre: 在请求被路由之前调用
* routing: 在路由请求时调用
* post: 在routing和error过滤器之后被调用
* error: 处理请求时发生错误时被调用
* @return
*/
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
/**
* 过滤器执行顺序,数值越小,优先级越高
* @return
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 过滤器是否要执行,可通过此方法指定过滤器的有效范围
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 过滤器的执行逻辑
* @return
*/
@Override
public Object run() {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
// 网关后面的微服务如果设置了spring security 中的basic Auth(即:不允许匿名访问,必须提供用户名、密码)
requestContext.addZuulRequestHeader("Authorization",
"Basic " + getBase64Credentials("admin", "admin"));
logger.info("======== zuul 路由 " + request.getMethod() + " " + request.getRequestURL().toString());
return null;
}
private String getBase64Credentials(String username, String password) {
String plainCreds = username + ":" + password;
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
return new String(base64CredsBytes);
}
}