Spring Cloud (十四)、API网关服务(入门)

在API网关服务入门示例中,我们来构建一个网关,来实现请求路由请求过滤的功能。

一、构建网关

1、创建一个基础的Spring Boot工程,命名为api-gateway。

2、编写pom.xml文件,具体内容如下:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.1.6.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.example</groupId>
   <artifactId>api-gateway</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>api-gateway</name>
   <description>Demo project for Spring Boot</description>

   <properties>
      <java.version>1.8</java.version>
      <spring-cloud.version>Greenwich.SR1</spring-cloud.version>
   </properties>

   <dependencies>
      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>

   <dependencyManagement>
      <dependencies>
         <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
         </dependency>
      </dependencies>
   </dependencyManagement>

   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>

</project>

       对于spring-cloud-starter-zuul依赖,可以通过查看它的内容了解到:该模块不仅包含了Netflix Zuul的核心依赖zuul-core,还包含了spring-cloud-starter-netflix-hystrix、spring-cloud-starter-netflix-ribbon、spring-boot-starter-actuator。 

3、在应用主类上使用@EnableZuulProxy注解来开启Zuul的API网关服务功能。

@EnableZuulProxy
@SpringCloudApplication
public class ApiGatewayApplication {

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

4、在application.properties中配置Zuul应用的基础信息:

spring.application.name=api-gateway
server.port=5555

完成以上的步骤我们就将网关服务构建完成。

二、请求路由 

我们使用已有的微服务应用,比如我在之前实验中的hello-service、fegin-consume。其他为服务也可以,没影响。

1、传统路由方式:需要维护微服务应用的具体实例位置。

       我们只需要在api-gateway服务中增加一些关于路由,规则的配置:

zuul.routes.api-a-url.path=/api-a/**
zuul.routes.api-a-url.url=http://localhost:5555/

 来访问http://localhost:5555/api-a/hello。API网关会将该请求路由到http://localhost:5555/hello提供的微服务接口上。

 

2、面向服务的路由

      Spring Cloud Zuul实现了与Spring Cloud Eureka的无缝整合,我们可以让路由的path不是映射具体的url,而是让它映射到某个具体的服务,而具体的url则交给Eureka的服务发现机制去自动维护。

步骤如下:

(1)、在api-gateway的pom.xml中引入eureka的依赖:

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

(2)、在api-gateway的application.properties配置文件中指定Eureka注册中心的位置,并且配置服务路由。

 

#面向服务的路由
zuul.routes.api-a.path=/api-a/**
zuul.routes.api-a.serviceId=hello-service

zuul.routes.api-b.path=/api-c/**
zuul.routes.api-b.serviceId=feign-consumer

eureka.client.service-url.defaultZone=http://localhost:1111/eureka/

      通过指定Eureka Server服务注册中心的位置,除了将自己注册成为服务之外,同时也让Zuul能够获取hello-service和fegin-consume服务的实例清单,以实现path映射服务,再从服务中挑选实例来进行请求转发的完整路由机制。

      以上分别定义了两个名为api-a、api-b的路由来映射hello-service和feig-consumer微服务应用。

(3)测试验证

  • 访问http://localhost:5555/api-a/hello:该url符合/api-a/**规则,由api-a路由负责转发,该路由映射的serviceId为hello-service,所以最终/hello请求会被转发到hello-service服务的某个实例上。

  • 访问http://localhost:5555/api-c/feign-consumer2:该url符合/api-c/**规则,由api-b路由负责转发,该路由映射的serviceId为feign-consumer,所以最终/feign-consumer2请求会被转发到feign-consumer服务的某个实例上。

三、请求过滤

       在API网关中实现啊对客户端请求的校验。通过定义过滤器来实现对请求的拦截与过滤,我们只需要继承ZuulFilter抽象类并实现它定义的4个抽象函数就可以完成请求的拦截和过滤了。

(1)、来定义一个简单的Zuul过滤器,它实现了在请求被路由之前检查HttpServletRequest中是否有accessToken参数,若有就进行路由,若没有就拒绝访问,返回401 Unauthorized错误。

public class AccessFilter extends ZuulFilter {
    private Logger logger = Logger.getLogger(String.valueOf(AccessFilter.class));

    /*过滤器的类型:决定过滤器在请求的哪个生命周期中执行。定义为pre,带包在请求被路由之前执行*/
    @Override
    public String filterType() {
        return "pre";
    }

    /*过滤器的执行顺序:当请求在一个阶段中存在多个过滤器时,需要根据该方法返回的值来一次执行*/
    @Override
    public int filterOrder() {
        return 0;
    }

    /*判断过滤器是否需要执行:为true表示该过滤器对所有的请求都会有效。实际运用中可以利用该函数来指定过滤器的有效范围*/
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /*过滤器的具体逻辑*/
    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        logger.info("send "+request.getMethod()+" request to "+request.getRequestURI().toString());
        Object accessToken = request.getParameter("accessToken");
        if(accessToken == null){
            logger.warning("access token is empty");
            //令zuul过滤该请求,不对其进行路由
            ctx.setSendZuulResponse(false);
            //设置返回的错误码
            ctx.setResponseStatusCode(401);
            return null;
        }
        logger.info("access tiken ok");
        return null;
    }
}

(2)、实现了自定义过滤器之后不会自动生效,需要为其创建具体的Bean才能启动该过滤器,比如,在应用主类增加以下内容:

@EnableZuulProxy
@SpringCloudApplication
public class ApiGatewayApplication {

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

	@Bean
	public AccessFilter accessFilter(){
		return new AccessFilter();
	}
}

(3)、测试验证

重新启动api-gateway应用,进行以下请求进行测试:

  • 访问http://localhost:5555/api-a/hello

  • 访问http://localhost:5555/api-a/hello?accessToken=token

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值