Spring Cloud 微服务架构搭建(五)— Netflix Zuul 路由网关及服务过滤
本文首发于:https://antoniopeng.com
Zuul 简介
Zuul
的主要功能是路由转发和过滤器。路由功能是微服务的一部分,比如 /api/admin
转发到到 Admin 服务,/api/member
转发到到 Member 服务。Zuul
默认和 Ribbon
结合实现了负载均衡的功能。
引入依赖
在 pom.xml
中主要添加 spring-cloud-starter-netflix-eureka-server
和 spring-cloud-starter-netflix-zuul
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
相关配置
在 application.yml
中主要添加 Zuul
路由配置
zuul:
routes:
api-a:
path: /api/ribbon/**
serviceId: hello-spring-cloud-web-admin-ribbon
api-b:
path: /api/feign/**
serviceId: hello-spring-cloud-web-admin-feign
路由说明:
- 以 /api/ribbon 开头的请求都转发给 spring-cloud-web-admin-ribbon 服务
- 以 /api/feign 开头的请求都转发给 spring-cloud-web-admin-feign 服务
在 Application
入口类中添加 @EnableZuulProxy
注解开启 zuul
功能
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
配置网关路由失败时的回调
创建 WebAdminFeignFallbackProvider
回调类
/** * 路由 hello-spring-cloud-web-admin-feign 失败时的回调 */
@Component
public class WebAdminFeignFallbackProvider implements FallbackProvider {
@Override
public String getRoute() {
// ServiceId,如果需要所有调用都支持回退,则 return "*" 或 return null
return "hello-spring-cloud-web-admin-feign";
}
/** * 如果请求服务失败,则返回指定的信息给调用者 * @param route * @param cause * @return */
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
/** * 网关向 api 服务请求失败了,但是消费者客户端向网关发起的请求是成功的, * 不应该把 api 的 404,500 等问题抛给客户端 * 网关和 api 服务集群对于客户端来说是黑盒 * @return * @throws IOException */
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return HttpStatus.OK.value();
}
@Override
public String getStatusText() throws IOException {
return HttpStatus.OK.getReasonPhrase();
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> map = new HashMap<>();
map.put("status", 200);
map.put("message", "无法连接");
return new ByteArrayInputStream(objectMapper.writeValueAsString(map).getBytes("UTF-8"));
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
// 和 getBody 中的内容编码一致
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
return headers;
}
};
}
}
测试路由访问
依次运行 EurekaApplication
> ServiceAdminApplication
> WebAdminRibbonApplication
> WebAdminFeignApplication
> ZuulApplication
各服务
- 访问:http://localhost:8769/api/ribbon/hi?message=zuul
浏览器显示
port : 8763,message : zuul
- 访问:http://localhost:8769/api/feign/hi?message=zuul
浏览器显示
port : 8763,message : zuul
至此说明 Zuul 的路由功能配置成功。
使用 Zuul 的服务过滤功能
Zuul
不仅仅只是路由,还有很多强大的功能。比如用在安全验证方面。
创建服务过滤器
/** * Zuul 的服务过滤演示 */
@Component
public class LoginFilter extends ZuulFilter {
private static final Logger logger = LoggerFactory.getLogger(LoginFilter.class);
/** * 配置过滤类型,有四种不同生命周期的过滤器类型 * 1. pre:路由之前 * 2. routing:路由之时 * 3. post:路由之后 * 4. error:发送错误调用 * @return */
@Override
public String filterType() {
return "pre";
}
/** * 配置过滤的顺序 * @return */
@Override
public int filterOrder() {
return 0;
}
/** * 配置是否需要过滤:true/需要,false/不需要 * @return */
@Override
public boolean shouldFilter() {
return true;
}
/** * 过滤器的具体业务代码 * @return * @throws ZuulException */
@Override
public Object run() throws ZuulException {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
String token = request.getParameter("token");
if (token == null) {
logger.warn("Token is empty");
context.setSendZuulResponse(false);
context.setResponseStatusCode(401);
try {
context.getResponse().getWriter().write("Token is empty");
} catch (IOException e) {
}
} else {
logger.info("OK");
}
return null;
}
}
测试过滤器
- 访问:http://localhost:8769/api/feign/hi?message=zuul
网页显示
Token is empty
- 访问:http://localhost:8769/api/feign/hi?message=zuul&token=1
网页显示
port : 8763,message : zuul