美文网首页
SpringCloud 之 Zuul(网关)

SpringCloud 之 Zuul(网关)

作者: 索性流年 | 来源:发表于2020-05-09 10:58 被阅读0次

概述

网关 Api(接口) Gateway(网关)--接口网关:接口是没有界面的

网关概念:

相当于客户端发送的请求先通过网关服务器,如若网关对该接口没有任何疑问,怎转发到接口服务器进行处理。

网关的作用:

网关可以拦截所有请求,对该请求做权限控制、负载均衡、日志管理、接口调用监控

网关与过滤器的区别:

过滤器适合于单个服务请求拦截,网关能拦截整个微服务请求

Nginx和zuul区别:

相同点:都可以实现负载均衡、反向代理、拦截请求、

不同点:Nginx采用C语言编写,Zuul采用Java语言。Zuul的负载本地均衡实现采用ribbon+eureka,Nginx的负载均衡是采用服务器端实现
Nginx相比Zuul功能会更加强大因为Nginx可以整合一些脚本语言(Lua),Nginx适合于服务器端服务器端负载均衡,Zuul适合用微服务网关

最好建议Nginx+Zuul实现网关,Nginx实现反向代理,Zuul实现请求拦截

接口是在什么情况下产生的?

接口是在面向服务架构,和微服务背景下产生的,目的都是为了解耦,在RPC远程调用中产生的。

接口是如何分类的?

开放接口-- 其他机构合作伙伴访问的接口(必须要在外网访问)例如蚂蚁支付,微信公众平台,需要通过APP-ID + APP-SOCET 生成 ACCESS-TOKEN 进通讯,目的是可以授权一些OAuth2.0(授权机制)接口权限

内部接口
一般只能在局域网之间访问,服务于服务调用之间关系,都在同一个微服务系统中。目的是为了保证安全问题

接口幂等性:

在调用接口的过程中,相同接口地址、相同参数同时发送多次请求
最终只会执行一次。
举个最简单的例子,那就是支付,用户购买商品后支付,支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额返发现多扣钱了,流水记录也变成了两条...,这就没有保证接口的幂等性

如若现在让你设计一套接口,你会如何设计?

考虑:接口权限(开发、内部)、幂等性、安全性(HTTPS)防止数据篡改(验签)、使用网关拦截接口(黑名单、白名单)、一般使用http+json格式 目的是为了跨平台、高并发(实现服务降级、熔断、隔离)、最后使用同一的API管理平台进行(api swagger)管理

步入正题,使用Zuul过滤所有请求

pom 文件配置

        <!--SprinCloud整合zuul网关-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>

        <!--SprinCloud整合Eureka客户端->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

yml配置


#服务注册地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8100/eureka/
#端口号
server:
  port: 80

spring:
  application:
    name: service-zuul

zuul:
  routes:
    api-a:
#      访问路径
      path: /api-member/**
#      服务别名
      serviceId: app-member
    api-b:
      path: /api/order/**
      serviceId: app-order

在启动方法中开启网关


@SpringBootApplication
@EnableEurekaClient
//开启网关
@EnableZuulProxy
public class SpringcloudZuulApplication {

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

}

新建Class继承 ZuulFilter(模拟拦截)


public class TokenFilter extends ZuulFilter {
    /*过滤器类型 pre标识在请求之前执行*/
    @Override
    public String filterType() {
        return "pre";
    }

    /*过滤器执行顺序*/
    @Override
    public int filterOrder() {
        return 0;
    }

    /*判断过滤器是否生效*/
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /*编写过滤器拦截业务*/
    @Override
    public Object run() throws ZuulException {
//        案例:拦截所有请求,判断是否有传递Token
//        1.获取上下文
        RequestContext currentContext = RequestContext.getCurrentContext();
//        2.获取Request对象
        HttpServletRequest request = currentContext.getRequest();
        //        获取参数
//        request.getParameter()
//        3.获取请求头token
        String token = request.getHeader("token");
//        判断token是否符合规范
        if (StringUtils.isEmpty(token)) {
//            返回错误提示,不会放行
            currentContext.setSendZuulResponse(false);
            currentContext.setResponseBody("token 为空");
            currentContext.setResponseStatusCode(401);
            return null;
        }
//        正常调用服务
        return null;
    }
}

新建ErrorFilter继承ZuulFilter(错误拦截)

 private static final Logger logger = LoggerFactory.getLogger(ErrorFilter.class);

    @Override
    public String filterType() {
        return "error";
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        try {
            RequestContext context = RequestContext.getCurrentContext();
            ZuulException exception = this.findZuulException(context.getThrowable());
            logger.error("进入系统异常拦截", exception);

            HttpServletResponse response = context.getResponse();
            response.setContentType("application/json; charset=utf8");
            response.setStatus(exception.nStatusCode);
            PrintWriter writer = null;
            try {
                writer = response.getWriter();
                writer.print("{code:" + exception.nStatusCode + ",message:\"" + "服务器异常" + "\"}");
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (writer != null) {
                    writer.close();
                }
            }

        } catch (Exception var5) {
            ReflectionUtils.rethrowRuntimeException(var5);
        }

        return null;
    }

    ZuulException findZuulException(Throwable throwable) {
        if (ZuulRuntimeException.class.isInstance(throwable.getCause())) {
            return (ZuulException) throwable.getCause().getCause();
        } else if (ZuulException.class.isInstance(throwable.getCause())) {
            return (ZuulException) throwable.getCause();
        } else {
            return ZuulException.class.isInstance(throwable) ? (ZuulException) throwable : new ZuulException(throwable, 500, (String) null);
        }
    }

发现404无法过滤,新建class继承ErrorController

@RestController
public class GlobalExceptionHandler implements ErrorController {
    /**
     * 出异常后进入该方法,交由下面的方法处理
     */
    @Override
    public String getErrorPath() {
        return "/error";
    }

    @RequestMapping("/error")
    public String error(HttpServletRequest request, HttpServletResponse response) {
        Integer status = (Integer)request.getAttribute("javax.servlet.error.status_code");
        System.err.println(status);
        return ReturnResult.failure(status,"请求异常");
    }
}

相关文章

网友评论

      本文标题:SpringCloud 之 Zuul(网关)

      本文链接:https://www.haomeiwen.com/subject/zkvdgctx.html