zuul
1.zuul介绍:
zuul是netflix公司的微服务网关(gateway)开源项目,zuul主要有请求路由,负载均衡,校验过滤等功能;
2.nginx + zuul + 微服务:
用户的请求指向nginx,nginx方向代理zuul的请求url;zuul对nginx发送过来的请求进行校验过滤,并路由到微服务工程
3.微服务内部之间调用认证问题:
当一个受保护的微服务资源调用另外一个受保护的微服务资源时,由于第二次调用没有携带token身份令牌和jwt令牌,因此第二次会被拒绝访问,解决办法:将jwt令牌和token令牌一层层往下传递,使用拦截器来完成
zuul的使用
1.引导类上加@EnableZuulProxy注解
@EnableZuulProxy
@SpringBootApplication
public class GateWayApplication{
public static void main(String[] args){
SpringApplication.run(GateWayApplication.class);
}
}
2.配置application.yml路由
zuul:
routes:
hello‐zuul-test1: #路由名称,名称任意,保持所有路由名称唯一
path: /course/** #路由拦截的url,匹配微服务一级@RequestMapping("/course")
serviceId: xc‐service‐manage‐course #指定服务id,从Eureka中找到服务的ip和端口
#url: http://localhost:31200 #也可指定url
strip‐prefix: false #true:代理转发时去掉前缀,false:代理转发时不去掉前缀
sensitiveHeaders: #敏感头设置,默认zuul会屏蔽cookie,cookie不会传到下游服务,这里设置为空则取消默认的黑名单,如果设置了具体的头信息则不会传到下游服务
ignoredHeaders: #可以设置过虑的头信息,默认为空表示不过虑任何头
hello‐zuul-test2:
...
3.自定义类继承ZuulFilter,重写四个方法:
filterType(): zuul过滤器执行的时机;pre路由前,routing路由时,error路由时异常,post路由后
filterOrder(): zuul过滤器链执行的顺序;返回0表示级别最高,其实是1,2...
shouldFilter(): zuul过滤器是否执行;true执行,false不执行
run(): zuul过滤器业务逻辑
@Component
public class CustomerFilter extends ZuulFilter {
@Override
public String filterType() {
return "pre"; //路由前
}
@Override
public int filterOrder() {
return 0; //过滤级别0
}
@Override
public boolean shouldFilter() {
return true; //开启过滤器
}
@Override
public Object run() throws ZuulException {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
HttpServletResponse response = context.getResponse();
//请求头没有Authorization的拒绝访问
String header = request.getHeader("Authorization");
if (StringUtils.isEmpty(header)) {
//拒绝访问
context.setSendZuulResponse(false);
ResponseResult responseResult = new ResponseResult(CommonCode.UNAUTHENTICATED);
String jsonStr = JSON.toJSONString(responseResult);
context.setResponseStatusCode(200);
context.setResponseBody(jsonStr);
response.setContentType("application/json;charset=utf-8");
return null;
}
return null;
}
}
4.zuul工程坐标
<!--zuul依赖坐标-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<!--zuul请求路由从eureka注册中心,订阅服务列表来完成路由-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
微服务间调用解决
1.自定义类实现RequestInterceptor接口
//RequestInterceptor拦截器只能拦截feign的远程调用,restTemplate不行
public class FeignClientInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
Enumeration<String> enumeration = request.getHeaderNames();
while (enumeration.hasMoreElements()) {
String headerName = enumeration.nextElement();
String headerValue = request.getHeader(headerName);
//将头信息保存到feign的远程调用请求
requestTemplate.header(headerName, headerValue);
}
}
}
2.在需要用到增强feign的引导类中,引入自定义拦截器
@Bean
public FeignClientInterceptor feignClientInterceptor(){
return new FeignClientInterceptor();
}
3.添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
4.如果是使用restTemplate进行远程调用,手动在httpEntity中添加需要的认证数据
HttpEntity<MultiValueMap> httpEntity = new HttpEntity<>(bodyMap, headerMap);
ResponseEntity<Map> responseEntity = restTemplate.exchange(authUrl, HttpMethod.POST, httpEntity, Map.class);