在Spring Cloud, Zuul默认已经整合了Hystrix,而且如果启动了Dashborad,也可以知道Zuul对Hystrix监控的粒度是微服务,而不是某一个API;同时也说明所有经过Zuul的请求都会被Hystrix保护起来。
为Zuul添加回退
想要为Zuul添加回退,需要实现FallbackProvider接口(Edgware.RELEASE以前的版本实现ZuulFallbackProvider接口,Edgware.RELEASE开始则为 FallbackProvider 接口)。在实现类中,指定为哪一个微服务提供回退,并且提供一个ClientHttpResponse作为回退响应。
编写Zuul回退类
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import com.netflix.hystrix.exception.HystrixTimeoutException;
@Component
public class MyFallbackProvider implements FallbackProvider {
@Override
public String getRoute() {
// 表明是为哪个微服务提供回退,*表示为所有微服务提供回退,使用serviceId的话,则为单个微服务
return "*";
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
if(cause instanceof HystrixTimeoutException) {
return response(HttpStatus.GATEWAY_TIMEOUT);
} else {
return response(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
private ClientHttpResponse response(final HttpStatus status) {
return new ClientHttpResponse() {
@Override
public HttpHeaders getHeaders() {
// headers 设定
HttpHeaders headers = new HttpHeaders();
MediaType mt = new MediaType("application", "json", Charset.forName("UTF-8"));
headers.setContentType(mt);
return headers;
}
@Override
public InputStream getBody() throws IOException {
// 响应体
return new ByteArrayInputStream("服务不可用,请稍后再试。".getBytes("UTF-8"));
}
@Override
public String getStatusText() throws IOException {
// 返回状态文本
return status.getReasonPhrase();
}
@Override
public HttpStatus getStatusCode() throws IOException {
return status;
}
@Override
public int getRawStatusCode() throws IOException {
// 返回数字类型的状态码
return status.value();
}
@Override
public void close() {
}
};
}
}
重新启动Eureka Server,eureka-client 以及 api-gateway。
我们正常通过zuul访问 eureka-client 微服务,访问接口没有问题。
然后我们关掉 eureka-client 微服务
再次访问接口,则会出现 “服务不可用,请稍后再试。” 而不是以前不友好的那个页面(默认的 /error 界面)了。