1. Cloud Discovery ☑️Eureka Server
Cloud Routing ☑️Zuul
2. ServiceZuulApplication
通过注解@EnableDiscoveryClient 向服务中心注册
通过注解@EnableZuulProxy 开启zuul的功能
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@EnableZuulProxy
@SpringBootApplication
public class ServiceZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceZuulApplication.class, args);
}
}
3. application.yml
以/api-a/ 开头的请求都转发给service-hi服务
以/api-b/ 开头的请求都转发给service-feign服务
server:
port: 8769
eureka:
instance:
hostname: localhost
client:
service-url:
default-zone: http://${eureka.instance.hostname}:8761/eureka/
spring:
application:
name: service-zuul
zuul:
routes:
api-a:
path: /api-a/**
serviceId: service-hi
api-b:
path: /api-b/**
serviceId: service-feign
4. 启动工程
Application | AMIs | Availability Zones | Status |
---|---|---|---|
SERVICE-FEIGN | n/a (1) | (1) | UP (1) - deair:service-feign:8765 |
SERVICE-HI | n/a (1) | (1) | UP (1) - deair:service-hi:8762 |
SERVICE-ZUUL | n/a (1) | (1) | UP (1) - deair:service-zuul:8769 |
访问http://localhost:8769/api-a/hi?name=
hi ,i am from port:8762
访问http://localhost:8769/api-b/hi?name=
hi ,i am from port:8762
说明zuul起到了路由的作用
5. 服务过滤
package org.kaidi.servicezuul.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class MyFilter extends ZuulFilter {
private static final Logger logger = LoggerFactory.getLogger(MyFilter.class);
/**
* 在zuul中定义了四种不同生命周期的过滤器类型
* 1. pre:路由之前
* 该类型的filters在Request Routing到源web-service之前执行 用来实现Authentication、选择源服务地址等
* 2. routing:路由之时
* 该类型的filters用于把Request Routing到源web-service,这里使用HttpClient请求web-service
* 3. post: 路由之后
* 该类型的filters在Routing返回Response后执行 用来实现对Response结果进行修改,收集统计数据以及把Response传输会客户端
* 4. error:发送错误调用
* 上面三个过程中任何一个出现错误都交由ERROR类型的filters进行处理
*
* @return
*/
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
/**
* 过滤优先级
* 数字越大, 优先级越低
*
* @return
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 这里可以写逻辑判断,是否要过滤,本文true,永远过滤
* 有时我们会动态的决定让不让一个filter生效
* 譬如我们可能根据Request里是否携带某个参数来判断是否需要生效,
* 或者我们需要从上一个filter里接收某个数据来决定,
* 再或者我们希望能手工控制是否生效(使用如Appolo之类的配置中心,来动态设置该字段)
*
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 过滤器的具体逻辑
* 可用很复杂,包括查sql,nosql去判断该请求到底有没有权限访问
*
* @return
*/
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
logger.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
// 获取传来的参数accessToken
Object accessToken = request.getParameter("access_token");
if (accessToken == null) {
logger.warn("access token is empty");
// 过滤该请求,不往下级服务去转发请求,到此结束
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
ctx.setResponseBody("{\"result\":\"access token is empty!\"}");
ctx.getResponse().setContentType("text/html;charset=UTF-8");
return null;
}
// 如果有accessToken,进行路由转发
logger.info("access token is ok");
return null;
}
}
访问http://localhost:8769/api-b/hi?name=
{"result":"access token is empty!"}
访问http://localhost:8769/api-b/hi?name=&access_token=
hi ,i am from port:8762
说明zuul起到了过滤的作用