前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringCloud入门系列之API网关

SpringCloud入门系列之API网关

作者头像
AI码真香
发布2022-09-13 15:32:35
4700
发布2022-09-13 15:32:35
举报
文章被收录于专栏:AI码真香
初识API网关

使用API网关有点

  • 统一访问出入口,微服务对前台透明
  • 安全,过滤,流控等API管理功能
  • 利于监控、方便管理

API网关产品

  • Netflix Zuul
    • Zuul 是Netflix开源的一个API网关, 核心实现是Servlet
    • Spring Cloud内置Zuul 1.x
    • Zuul 1.x 核心实现是Servlet,采用同步方式通信
    • Zuul 2.x 基于Netty Server,提供异步通信
  • Spring Cloud Gateway
    • Spring Cloud Gateway,是Spring自己的项目
    • Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式
    • Gateway基于Spring 5.0与Spring WebFlux开发,采用Reactor响应式设计
一、Zuul入门使用
1.1、pom.xml添加依赖
代码语言:javascript
复制
<?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>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.15.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.codesofun</groupId>
    <artifactId>zuul</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>zuul</name>
    <description>Demo project for Spring Boot</description>

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

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <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>
1.2、启动类添加注解@EnableZuulProxy

网管Zulul也是一个微服务客户端,所以入口类上也需要添加@EnableEurekaClient@EnableDiscoveryClient

代码语言:javascript
复制
package com.codesofun.zuul;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class ZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class, args);
    }
}
1.3、添加application.properties配置
代码语言:javascript
复制
spring.application.name=zuul-proxy
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
#微服务实例接口映射路径
zuul.routes.book-service-api.path=/bs/**
#微服务实例ID
zuul.routes.book-service-api.service-id=book-service

zuul.routes.member-service-api.path=/ms/**
zuul.routes.member-service-api.service-id=member-service

zuul.routes.message-service-api.path=/sms/**
zuul.routes.message-service-api.service-id=message-service

#端口一般为80 或 443
server.port=443
二、Zuul负载均衡与服务降级
2.1、负载均衡

Spring Cloud Zuul内置Ribbon,与标准配置相同,局部配置如下:

代码语言:javascript
复制
#局部设置网关与 book-service 微服务通信负载均衡策略
book-service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule

全局配置可以放在bean 配置类中交给IOC容器管理,主要配置如下:

代码语言:javascript
复制
    @Bean
    public IRule ribbonRule(){
        return new RandomRule();
    }
2.2、配置服务降级

Spring Cloud Zuul内置Hystrix,服务降级需要实现接口FallbackProvider,如下:

代码语言:javascript
复制
package com.codesofun.zuul.fallback;

import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

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

/**
 * @ClassName BookServiceFallBack
 * @Description Book-service 服务降级
 * @Author mozhijun
 * @Date 2020/7/8 15:43
 * @Version 1.0
 **/
@Component
public class BookServiceFallBack implements FallbackProvider {

    /**
     * 设置为哪个微服务提供降级
     */
    @Override
    public String getRoute() {
        return "book-service";
    }

    /**
     * 描述: 降级处理逻辑
     * @Author mozhijun
     * @Date 15:45 2020/7/8
     * @param route 服务ID
     * @param cause 抛出的异常信息
     * @return org.springframework.http.client.ClientHttpResponse 服务降级response
     */
    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        return new ClientHttpResponse() {

            /**
             * 响应状态码
             */
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.OK;
            }

            /**
             * 数字状态
             */
            @Override
            public int getRawStatusCode() throws IOException {
                return 200;
            }

            /**
             * 状态文本说明
             */
            @Override
            public String getStatusText() throws IOException {
                return "ok";
            }

            /**
             * 关闭的回收触发,一般用于资源的释放
             */
            @Override
            public void close() {

            }

            /**
             * 响应给客户端的内容
             */
            @Override
            public InputStream getBody() throws IOException {
                return new ByteArrayInputStream("Book Service is unavailable".getBytes());
            }

            /**
             * 响应头信息
             */
            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.TEXT_HTML);
                return headers;
            }
        };
    }
}

getRoute()中返回指定微服务的实例名称,设置所有微服务默认降级回调,这里只需要返回*即可

代码语言:javascript
复制
    /**
     * 设置为哪个微服务提供降级
     */
    @Override
    public String getRoute() {
        return "book-service";
    }
三、基于RateLimit实现网关限流

微服务网关流量控制

  • 微服务网关是应用入口,必须对入口流量进行控制
  • RateLimit是Spring Cloud Zuul的限流组件 开源网站地址https://github.com/marcosbarbero/spring-cloud-zuul-ratelimit
  • RateLimit采用令牌桶算法实现限流

RateLimit使用步骤

3.1、pom.xml添加依赖
代码语言:javascript
复制
<?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>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.15.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.codesofun</groupId>
    <artifactId>zuul-ratelimit</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>zuul-ratelimit</name>
    <description>Demo project for Spring Boot</description>

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

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
        <dependency>
            <groupId>com.marcosbarbero.cloud</groupId>
            <artifactId>spring-cloud-zuul-ratelimit</artifactId>
            <version>2.2.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
            <scope>runtime</scope>
        </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>
3.2、配置存储组件

这里存储使用关系型数据库mysql,orm框架使用jpa,添加配置如下:

代码语言:javascript
复制
spring.application.name=zuul-proxy
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
############ zuul ############
#微服务实例接口映射路径
zuul.routes.book-service-api.path=/bs/**
#微服务实例ID
zuul.routes.book-service-api.service-id=book-service

zuul.routes.member-service-api.path=/ms/**
zuul.routes.member-service-api.service-id=member-service

zuul.routes.message-service-api.path=/sms/**
zuul.routes.message-service-api.service-id=message-service
#开启zuul限流,默认false
zuul.ratelimit.enabled=true
# 对应存储类型(用来统计存储统计信息)
zuul.ratelimit.repository=jpa
########## 数据源 #########
spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=mzj584wanlhy
spring.jpa.database-platform=org.hibernate.dialect.MySQL57InnoDBDialect
spring.jpa.show-sql=true
#局部设置网关与 book-service 微服务通信负载均衡策略
book-service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
#端口一般为80 或 443
server.port=443

创建表**rate**

代码语言:javascript
复制
CREATE TABLE rate (
  rate_key VARCHAR(255) NOT NULL,
  remaining BIGINT,
  remaining_quota BIGINT,
  reset BIGINT,
  expiration TIMESTAMP,
  PRIMARY KEY(rate_key)
);
3.3、配置限流策略
代码语言:javascript
复制
######默认限流策略全局配置: 对同一个url请求 5秒内最多10次,其余会被限流###########
#每个刷新时间窗口对应的请求数量限制
zuul.ratelimit.default-policy-list[0].limit=10
#每个刷新时间窗口对应的请求时间限制(秒)
zuul.ratelimit.default-policy-list[0].quota=1000
# 刷新时间窗口的时间,默认值 (秒)
zuul.ratelimit.default-policy-list[0].refresh-interval=5
#限流方式
zuul.ratelimit.default-policy-list[0].type=url

####在zuul与book-service通信时,每2秒内,只允许2个请求访问,其余进来的请求会被限制访问,并返回状态码429#####
# 每秒允许多少个请求
zuul.ratelimit.policy-list.message-service-api[0].limit=2
# 刷新时间(单位秒)
zuul.ratelimit.policy-list.message-service-api[0].refresh-interval=2
#限流方式: 可选user(用户限制) origin(请求限制) url(对同一个url访问限制) http_method
zuul.ratelimit.policy-list.message-service-api[0].type=origin

zuul.ratelimit.policy-list.member-service-api[0].limit=2
zuul.ratelimit.policy-list.member-service-api[0].refresh-interval=2
zuul.ratelimit.policy-list.member-service-api[0].type=origin

zuul.ratelimit.policy-list.book-service-api[0].limit=2
zuul.ratelimit.policy-list.book-service-api[0].refresh-interval=2
zuul.ratelimit.policy-list.book-service-api[0].type=origin
四、Zuul自定义过滤器

自定义过滤器,需要继承com.netflix.zuul.ZuulFilter类,这里模拟一个TOKEN校验的过滤器,具体如下:

代码语言:javascript
复制
package com.codesofun.zuul.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.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * @ClassName SecurityFilter
 * @Description 自定义安全过滤器
 * @Author mozhijun
 * @Date 2020/7/9 16:58
 * @Version 1.0
 **/
@Component
public class SecurityFilter extends ZuulFilter {

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

    /**
     * 执行顺序
     */
    @Override
    public int filterOrder() {
        return 6;
    }

    /**
     * 当前过滤器是否被执行
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        //获取上下文
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        String token = request.getHeader("token");
        if (StringUtils.isEmpty(token)) {
            //对该请求禁止路由,也就是禁止访问下游服务
            context.setSendZuulResponse(false);
            //状态码
            context.setResponseStatusCode(403);
            context.setResponseBody("{\"code\":403,\"message\":\"Token is unavailable\"}");
            return null;
        }
        //校验Token正确性代码
        context.setSendZuulResponse(true);
        context.setResponseStatusCode(200);
        return null;
    }
}

详细代码见仓库:https://gitee.com/xmlvhy/springcloud-learn 参考链接:http://www.itlaoqi.com/

代码语言:txt
复制
                                 本文作者: [AI码真香](https://www.xmlvhy.com/about) 
代码语言:txt
复制
                                 本文标题:                                     [SpringCloud入门系列之API网关](https://www.xmlvhy.com/article/detail/91.html) 
代码语言:txt
复制
                                 本文网址:                                     [https://www.xmlvhy.com/article/91.html](https://www.xmlvhy.com/article/detail/91.html) 
代码语言:txt
复制
                                 版权说明: 自由转载-非商用-非衍生-保持署名                                     [                                         署名-非商业性使用4.0 国际 (CC BY-NC 4.0)                                     ](https://creativecommons.org/licenses/by-nc/4.0/deed.zh) 

类似文章

  1. SpringCloud入门系列之配置中心
  2. SpringCloud入门系列之微服务之间的通信
  3. SpringCloud入门系列之服务链路追踪Sleuth&Zipkin
  4. SpringCloud入门系列之Eureka注册中心
  5. Redis 客户端常用命令
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 初识API网关
    • 一、Zuul入门使用
      • 1.1、pom.xml添加依赖
      • 1.2、启动类添加注解@EnableZuulProxy
      • 1.3、添加application.properties配置
    • 二、Zuul负载均衡与服务降级
      • 2.1、负载均衡
      • 2.2、配置服务降级
    • 三、基于RateLimit实现网关限流
      • 3.1、pom.xml添加依赖
      • 3.2、配置存储组件
      • 3.3、配置限流策略
    • 四、Zuul自定义过滤器
    相关产品与服务
    负载均衡
    负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档