栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【Spring Cloud Netflix】03--Zuul API网关

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Spring Cloud Netflix】03--Zuul API网关

一,统一的访问入口 1.新建网关模块
     创建sping boot项目  sp06 - zuul


2.修改pom.xml

eureka client
zuul
sp01



    
        springcloud1
        com.drhj
        0.0.1-SNAPSHOT
    
    4.0.0

    com.drhj
    sp06-zuul
    0.0.1-SNAPSHOT
    sp06-zuul
    Demo project for Spring Boot
    
        1.8
    
    
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        

        
            org.springframework.cloud
            spring-cloud-starter-netflix-zuul
        
        
            com.drhj
            sp01-commons
            0.0.1-SNAPSHOT
        

    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


3.application.yml配置

路由转发规则

spring:
  application:
    name: zuul
server:
  port: 3001
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka,http://eureka2:2002/eureka
# **包含深层路径
# * 只包含一层路径
# 服务id设置成功访问子路径,是默认规则
# zuul根据注册表的注册信息完成自动配置
# 最好手动配置
zuul:
  routes:
    item-service: /item-service/**
    user-service: /user-service/**
    order-service: /order-service/**
4.在启动类添加@EnableZuulProxy
package com.drhj.sp06;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@EnableZuulProxy
@SpringBootApplication
public class Sp06ZuulApplication {

    public static void main(String[] args) {
        SpringApplication.run(Sp06ZuulApplication.class, args);
    }

}
5.测试

注意将之前的人为阻塞注销

启动网关服务,访问如下网页进行测试
http://localhost:3001/item-service/iu56y4t3

http://localhost:3001/user-service/8

http://localhost:3001/user-service/8/score?score=100

http://localhost:3001/order-service/8o7i6u5y4t

http://localhost:3001/order-service/add

二,统一的权限校验

1.编写拦截类

1)新建ZuulFilter 子类
2)按zuul的规则实现
3)添加@Component注解

package com.drhj.sp06.filter;

import cn.drhj.web.util.JsonResult;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

@Component
public class AccessFilter extends ZuulFilter {
    //过滤器的类型:pre,route,post,error
    @Override
    public String filterType() {
        //return “pre”
        return FilterConstants.PRE_TYPE;
    }
    //顺序号
    @Override
    public int filterOrder() {
        return 6;
    }
    //针对当前请求进行判断
    //是否要执行下面的过滤代码
    @Override
    public boolean shouldFilter() {
        //调用后台商品服务需要检查权限
        //调用用户和订单可以直接访问
        //获得RequestContext对象
        RequestContext ctx = RequestContext.getCurrentContext();
        //从上下文对象获取访问的后台服务id
        String serviceId = (String)ctx.get(FilterConstants.SERVICE_ID_KEY);//“service”
        //判断服务id是否是"item-service"
        return "item-service".equals(serviceId);
    }
    //过滤代码,检查用户权限
    @Override
    public Object run() throws ZuulException {
        //http://localhost:3001/item-service/t45t4?token=123456
        //获取请求上下文对象
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        //接收token参数
        String token = request.getParameter("token");
        //如果没有token,阻止继续调用,直接返回响应
        if (StringUtils.isBlank(token)) {
            //阻止继续调用
            ctx.setSendZuulResponse(false);
            //直接返回响应
            //JsonResult -- {code:400,msg:未登录,data:null}
            String json = JsonResult.err().code(400).msg("Not Login,未登录").toString();
            ctx.addZuulResponseHeader("Content-Type","application/json;charset=UTF-8");
            ctx.setResponseBody(json);
        }
        //zuul当前版本中,这个返回值不起任何作用
        return null;
    }
}
2.测试

重启zuul网关服务
测试不含有参数token的网址 http://localhost:3001/item-service/t45t4

测试含有参数token的网址 http://localhost:3001/item-service/t45t4?token=100

三,Zuul集成Ribbon负载均衡和重试 1.说明

1)zuul默认启用了负载均衡
2)zuul默认没有启用重试
因为在入口位置进行重试,会造成后台大面积服务压力翻倍,可能造成故障传播,雪崩

2.zuul启用重试(不推荐) 在网关服务的pom.xml中添加spring-retry依赖

    org.springframework.retry
    spring-retry

配置网关服务的applition.yml
spring:
  application:
    name: zuul
server:
  port: 3001
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka,http://eureka2:2002/eureka
# **包含深层路径
# * 只包含一层路径
# 服务id设置成功访问子路径,是默认规则
# zuul根据注册表的注册信息完成自动配置
# 最好手动配置
zuul:
  routes:
    item-service: /item-service/**
    user-service: /user-service/**
    order-service: /order-service/**
  retryable: true
# 对所有服务的通用配置
ribbon:
  MaxAutoRetries: 1
#针对一个服务单独配置重试参数    
item-service:
  ribbon:
    MaxAutoRetries: 0
测试

打开之前写的手动阻塞

访问 http://localhost:3001/item-service/t45t4?token=100

查看后台
8001端口

8002端口

可见,实现了负载均衡,itemservice由于被设置了不允许重试,所以只执行一次,没有发生重试,只是更换了服务器

四,Zuul集成Hystrix 容错和限流 1.介绍

Hystrix是容错和限流工具
1)Hystrix容错 – 降级
调用后台服务出错(异常,阻塞,服务崩溃),可以执行当前服务的一段代码,直接向客户端返回降级结果

  • 错误提示
  • 缓存的结果
  • 根据业务逻辑,返回任意的结果
    2)Hystrix限流 – 熔断
  • 当流量过大,造成后台服务故障,可以断开链路,限制后台服务的访问流量,等待后台服务恢复
  • 断路器打开的条件
    10秒20次请求(必须首先满足)
    50%出错,执行降级代码
  • 半开状态
    断路器打开一段时间后,会进入半开状态
    会尝试发送一次客户端调用,
    – 0成功,关闭断路器,恢复正常
    – 失败,继续保持打开状态
2.Hystrix降级 Zuul默认已启用Hystrix


所以不用添加依赖了

实现FallbackProvider接口

按zuul的规则实现接口的方法
编写item-service的降级类

package com.drhj.sp06.fb;

import cn.drhj.web.util.JsonResult;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

@Component
public class ItmFB implements FallbackProvider {
    
    @Override
    public String getRoute() {
        return "item-service";
    }
    //发送给客户端的降级响应
    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        return new ClientHttpResponse() {
            //封装500状态码和error状态文本
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.INTERNAL_SERVER_ERROR;
            }
            //返回500
            @Override
            public int getRawStatusCode() throws IOException {
                return HttpStatus.INTERNAL_SERVER_ERROR.value();
            }
            //返回error状态文本
            @Override
            public String getStatusText() throws IOException {
                return HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase();
            }

            @Override
            public void close() {

            }
            //返回自定义结果
            @Override
            public InputStream getBody() throws IOException {
                //JsonResult - {code:500,msg:调用商品失败,data:null}
                String json = JsonResult.err().code(500).msg("调用商品失败").toString();
                return new ByteArrayInputStream(json.getBytes("UTF-8"));
                //BAIS流内存数组的流,不占用底层系统资源,不需要关闭
            }
            //设置返回的数据类型
            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders h = new HttpHeaders();
                h.add("Content-Type","application/json;charset=UTF-8");
                return h;
            }
        };
    }
}

编写order-service的降级类

package com.drhj.sp06.fb;

import cn.drhj.web.util.JsonResult;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

@Component
public class OrderFB implements FallbackProvider {
    
    @Override
    public String getRoute() {
        return "order-service";
    }
    //发送给客户端的降级响应
    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        return new ClientHttpResponse() {
            //封装500状态码和error状态文本
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.INTERNAL_SERVER_ERROR;
            }
            //返回500
            @Override
            public int getRawStatusCode() throws IOException {
                return HttpStatus.INTERNAL_SERVER_ERROR.value();
            }
            //返回error状态文本
            @Override
            public String getStatusText() throws IOException {
                return HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase();
            }

            @Override
            public void close() {
                //用来关闭下面方法中的流
                //BAIS 流内存数组的流,不占用底层系统资源,不需要关闭
            }
            //返回自定义结果
            @Override
            public InputStream getBody() throws IOException {
                //JsonResult - {code:500,msg:调用商品失败,data:null}
                String json = JsonResult.err().code(500).msg("调用订单失败").toString();
                return new ByteArrayInputStream(json.getBytes("UTF-8"));
            }
            //设置返回的数据类型
            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders h = new HttpHeaders();
                h.add("Content-Type","application/json;charset=UTF-8");
                return h;
            }
        };
    }
}
测试

访问item-service 服务的网址
http://localhost:3001/item-service/t45t4?token=100
由于阻塞会降级

访问order-service 服务的网址
http://localhost:3001/order-service/1

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/337791.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号