Spring Cloud进阶之路 | 七:服务网关(zuul)

简介

官方说明

Zuul is the front door for all requests from devices and web sites to the backend of the Netflix streaming application. As an edge service application, Zuul is built to enable dynamic routing, monitoring, resiliency and security. It also has the ability to route requests to multiple Amazon Auto Scaling Groups as appropriate.

简而言之,Zuul是从设备和网站到应用程序后端的所有请求的大门,旨在实现动态路由,监控,弹性和安全性。

zuul可以做什么

Zuul使用了含有不同类型的过滤器,这些过滤器可实现以下功能:

  • 身份验证和安全性,识别每个资源的身份验证要求,并拒绝不满足要求的请求。

  • 追踪监控,在边界跟踪有意义的数据和统计信息,以便为我们提供准确的生产视图。

  • 动态路由,根据需要将请求动态路由到不同的后端群集。

  • 压力测试,逐渐增加到群集的流量以评估性能。

  • 负荷控制,为每种类型的请求分配容量,并丢弃超出限制的请求。

  • 静态响应处理,直接在边界构建响应,而不是将其转发到内部服务集群

为什么要有网关

简单来言,网关就是路由转发+请求过滤。

如文章开头所述,在服务网关中可以很方便的完成一系列的切面功能,如权限校验、审计、接口监控、限流以及日志收集等。而且还可以和服务注册中心联动,免于配置众多微服务的地址、端口等繁杂配置,可直接通过服务发现来自动寻找并调用。

如果这些特性每个下游微服务都做一遍,其难度和工作量可想而知。所以,网关的重要性便不言而喻。

详细可参考文章:为啥要有服务网关

创建商品工程

复用之前文章中的xmall-product工程,并启动,端口为8080。

创建网关工程

pom依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
​
    <parent>
        <groupId>com.luas.cloud</groupId>
        <artifactId>java-boot-parent-2.1</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../../java-boot-parent-2.1</relativePath>
    </parent>
​
    <groupId>com.luas.xmall</groupId>
    <artifactId>xmall-zuul</artifactId>
    <version>1.0.0-SNAPSHOT</version>
​
    <name>xmall-zuul</name>
    <description>网关服务</description>
​
    <properties>
    </properties>
​
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
​
        <!-- nacos cloud -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
​
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
​
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
​
​
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
​
</project>

nacos配置

spring:
  application:
    name: xmall-zuul
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yml
      discovery:
        server-addr: 127.0.0.1:8848

路由规则

在application.yml中配置路由规则。

server:
  port: 5566
​
​
zuul:
  prefix: /gateway
  sensitive-headers:
  routes:
    product:
      path: /product/**
      service-id: xmall-product
      strip-prefix: true

其中,prefix为统一前缀,起到标识及路径统一的作用,可自动过滤(zuul.strip-prefix=true)。路由规则routes含义如下:

  • 规则标识ID,唯一标识路由规则,无其它特殊含义,后续其它组件可能会用到。

  • path,ant风格路径匹配规则,如/product/**,代表凡"/product"开头路径均转发到xmall-product服务

  • strip-prefix,是否过滤前缀,此前缀为path中的前缀,如过滤,真实转发路径中将过滤掉此前缀。

以本配置为例,访问http://localhost:5566/gateway/product/sku/1122,真实转发到xmall-product服务的请求路径为/sku/1122,gateway、product已被过滤掉。

开启网关功能

通过@EnableZuulProxy注解开启zuul网关功能。

package com.luas.xmall.gateway;
​
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
​
@EnableZuulProxy
@SpringBootApplication
public class XmallZuulApplication {
​
    public static void main(String[] args) {
        SpringApplication.run(XmallZuulApplication.class, args);
    }
​
}

启动网关工程,端口为5566。

访问http://localhost:8080/sku/1122,正常展示商品信息。

访问http://localhost:5566/gateway/product/sku/1122,依然正常展示商品信息。

zuul网关成功将请求路由到商品服务。

身份认证

前面说过,网关一个重要作用,便是身份认证。身份认证包含两个方面,认证和鉴权,这里只简单介绍一下认证。

创建前置身份认证过滤器

zuul过滤器分为四种,分别为:

  • pre,路由前调用

  • route,路由时调用

  • post,路由后调用

  • error,发生错误时调用

创建pre类型的身份认证过滤器,对请求进行身份认证,以token(query类型)为例。

package com.luas.xmall.gateway.filter;
​
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
​
import javax.servlet.http.HttpServletRequest;
​
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
​
@Component
public class PreAuthenticationFilter extends ZuulFilter {
​
    private Logger logger = LoggerFactory.getLogger(getClass());
​
    @Override
    public String filterType() {
        return PRE_TYPE;
    }
​
    @Override
    public int filterOrder() {
        return 0;
    }
​
    @Override
    public boolean shouldFilter() {
        return true;
    }
​
    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
​
        logger.info(String.format("[%s] url process", request.getRequestURL().toString(), request.getMethod()));
​
        String token = request.getParameter("token");
​
        if (StringUtils.isBlank(token)) {
            logger.warn("token is empty");
​
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
​
            try {
                ctx.getResponse().getWriter().write("token is empty.");
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }
        
        return null;
    }
}

filterOrder方法返回的为过滤器执行顺序,数字越小,顺序越靠前。

shouldFilter方法为判断方法,返回是否需要执行过滤逻辑,即run方法。可根据业务场景,自行编写判断逻辑。

至于run方法,当然就是过滤器重要逻辑本身了,可做许多操作。如本例,从request中取出token(query参数形式),判断并做相应判断和响应

重启网关工程,重新访问http://localhost:5566/gateway/product/sku/1122,结果如下:

控制台输出了Request Method、url信息,并警告token为空。

假设我们访问了授权服务,拿到了token,再次访问http://localhost:5566/gateway/product/sku/1122?token=0000,正常展示了商品信息。

PreAuthenticationFilter已成功生效,拦截了未授权请求,放过了已授权请求。

源码

github

https://github.com/liuminglei/SpringCloudLearning/tree/master/07/

gitee

https://gitee.com/xbd521/SpringCloudLearning/tree/master/07/


正文完

微信搜索【银河架构师】,发现更多精彩内容。

发布了29 篇原创文章 · 获赞 1 · 访问量 2236

猜你喜欢

转载自blog.csdn.net/liuminglei1987/article/details/104003890