李锋镝的博客

  • 首页
  • 时间轴
  • 左邻右舍
  • 关于我
    • 关于我
    • 另一个网站
    • 我的导航站
    • 网站地图
    • 赞助
    • 博友圈
  • 说说
  • 走心评论
  • 互动榜
  • 留言
  • 🚇开往
Destiny
自是人生长恨水长东
  1. 首页
  2. 原创
  3. 正文

从零搭建Spring Cloud Gateway网关(一)

2020年3月18日 567点热度 2人点赞 6条评论

新建Spring Boot项目

怎么新建Spring Boot项目这里不再具体赘述,不会的可以翻看下之前的博客或者直接百度。这里直接贴出对应的pom文件。

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>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/>
    </parent>
    <groupId>com.lifengdi</groupId>
    <artifactId>gateway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gateway</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR3</spring-cloud.version>
    </properties>

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <optional>true</optional>
        </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>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.5</version>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.58</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </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-boot-starter-web相关的依赖。

配置文件如下:

server:
  port: 8080
spring:
  application:
    name: spring-cloud-gateway-demo
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #启用路由访问
      routes:
        - id: path_route
          # 指定域名
          uri: http://localhost:8081
          predicates:
            - Path=/jar/**
          filters:
            # 熔断配置
            - name: Hystrix
              args:
                name: default
                fallbackUri: forward:/fallback
        - id: path_route2
          # 指定域名
          uri: http://localhost:8082
          predicates:
            - Path=/war/**
          filters:
            # 熔断配置
            - name: Hystrix
              args:
                name: hystrix1
                fallbackUri: forward:/fallback

  mvc:
    throw-exception-if-no-handler-found: true

# 默认熔断超时时间30s
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000
    hystrix1:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 1000

熔断(接口或者项目)

熔断相关jar包如下:

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

默认的熔断回调接口:

package com.lifengdi.gateway.hystrix;

import com.lifengdi.gateway.exception.BaseException;
import com.lifengdi.gateway.response.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author: Li Fengdi
 * @date: 2020-03-18 16:35
 */
@RestController
@Slf4j
public class DefaultHystrixController {
    @RequestMapping("/fallback")
    public ResponseResult<Object> fallback(){

        log.error("触发熔断......");
        return ResponseResult.fail(BaseException.DEFAULT_HYSTRIX.build());
    }
}

具体配置文件说明如下:

      routes:
        - id: path_route
          # 指定域名
          uri: http://localhost:8081
          predicates:
            - Path=/jar/**
          filters:
            # 熔断配置
            - name: Hystrix
              args:
                name: default
                fallbackUri: forward:/fallback
        - id: path_route2
          # 指定域名
          uri: http://localhost:8082
          predicates:
            - Path=/war/**
          filters:
            # 熔断配置
            - name: Hystrix
              args:
                name: hystrix1
                fallbackUri: forward:/fallback

  mvc:
    throw-exception-if-no-handler-found: true

# 默认熔断超时时间30s
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000
    hystrix1:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 1000

default、hystrix1为自定义的参数,可以配置多个熔断策略,不同的接口、服务可以单独配置对应的超时时间,不需要额外的进行开发,不过需要增加额外的配置文件。

全局session共享

依赖jar包:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

相关yml配置:

spring:
  redis:
    database: 0
    host: localhost
    port: 6379
    password: 123456
    lettuce:
      pool:
        max-active: 300
        max-idle: 8
        max-wait: -1ms
        min-idle: 0
  session:
    store-type: redis

spring.session.store-typeSpring默认就是redis实现的,也有其他的,配置不同罢了。

增加代码如下:

权限相关,这里默认全部放行:

package com.lifengdi.gateway.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;

@Configuration
@EnableWebFluxSecurity
public class GatewaySecurityConfig {
    @Bean
    SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity serverHttpSecurity)
            throws Exception {
        serverHttpSecurity
                .csrf().disable()
                .authorizeExchange().pathMatchers("/**").permitAll()
                .anyExchange()
                .authenticated();
        return serverHttpSecurity.build();
    }
}

session相关:

package com.lifengdi.gateway.config;

import com.lifengdi.gateway.resolver.MyCookieWebSessionIdResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.ResponseCookie;
import org.springframework.session.data.redis.config.annotation.web.server.EnableRedisWebSession;
import org.springframework.web.server.session.CookieWebSessionIdResolver;
import org.springframework.web.server.session.WebSessionIdResolver;

import java.util.function.Consumer;

@Configuration
@EnableRedisWebSession(maxInactiveIntervalInSeconds = 10*60*60, redisNamespace = "my:spring:session")
public class WebSessionConfig {

    @Bean
    public WebSessionIdResolver webSessionIdResolver() {
        CookieWebSessionIdResolver resolver = new MyCookieWebSessionIdResolver();
        resolver.setCookieName("SESSIONID");

        Consumer<ResponseCookie.ResponseCookieBuilder> consumer = responseCookieBuilder -> {
            responseCookieBuilder.path("/");
        };
        resolver.addCookieInitializer(consumer);
        return resolver;
    }

}

注意这里使用的是@EnableRedisWebSession注解,而不是@EnableRedisHttpSession,这个是和zuul不一样的地方。

用zuul做网关的时候,直接使用@EnableRedisHttpSession在配置里面就可以通过redis共享session信息

Spring同时提供了@EnableRedisWebSession来对WebFlux的支持。

值得一提的是这两个注解内部实现并不相同,需要自定义的配置也不一样。

这里自定义cookieName、path等是自定义了webSessionIdResolver来实现的,而不是cookieSerializer。如果使用cookieSerializer的话,对@EnableRedisWebSession来说是不起作用的。这个坑之前坑了好半天!

MyCookieWebSessionIdResolver代码如下:

package com.lifengdi.gateway.resolver;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpCookie;
import org.springframework.session.web.http.DefaultCookieSerializer;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.session.CookieWebSessionIdResolver;

import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 自定义WebSessionId解析器,以兼容{@link org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession}
 * <p>
 * 使用EnableRedisHttpSession时{@link DefaultCookieSerializer}中useBase64Encoding默认为true,将cookie中的sessionId使用base64
 * 加密,但是如果使用{@link org.springframework.session.data.redis.config.annotation.web.server.EnableRedisWebSession},默认
 * 的解析器没有将sessionId解密,导致获取不到正确的session
 * </p>
 *
 * @author: Li Fengdi
 * @date: 2020/3/16 15:41
 */
@Slf4j
public class MyCookieWebSessionIdResolver extends CookieWebSessionIdResolver {

    @Override
    public List<String> resolveSessionIds(ServerWebExchange exchange) {
        MultiValueMap<String, HttpCookie> cookieMap = exchange.getRequest().getCookies();
        List<HttpCookie> cookies = cookieMap.get(getCookieName());
        if (cookies == null) {
            return Collections.emptyList();
        }
        return cookies.stream().map(HttpCookie::getValue).map(this::base64Decode).collect(Collectors.toList());
    }

    /**
     * base64解码
     *
     * @param base64Value base64Value
     * @return 解码后的字符串
     */
    private String base64Decode(String base64Value) {
        try {
            byte[] decodedCookieBytes = Base64.getDecoder().decode(base64Value);
            return new String(decodedCookieBytes);
        } catch (Exception ex) {
            log.debug("Unable to Base64 decode value: " + base64Value);
            return null;
        }
    }

}

其实这段代码本就是参考了cookieSerializer中的代码来实现的。

如果指定了useBase64Encoding为false,即不加密sessionId,那么就不需要这一段代码了。

代码已上传到git上,需要的可以去看看。

git代码地址:https://github.com/lifengdi/spring-cloud-gateway-demo

除非注明,否则均为李锋镝的博客原创文章,转载必须以链接形式标明本文链接

本文链接:https://www.lifengdi.com/article/1776

相关文章

  • 从零搭建Spring Cloud Gateway网关(二)—— 打印请求响应日志
  • 从零搭建Spring Cloud Gateway网关(三)——报文结构转换
  • SpringBoot常用注解
  • CompletableFuture使用详解
  • SpringBoot 中内置的 49 个常用工具类
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
标签: JAVA Spring Cloud Spring Cloud Gateway SpringBoot 网关
最后更新:2021年5月12日

李锋镝

既然选择了远方,便只顾风雨兼程。

打赏 点赞
< 上一篇
下一篇 >
1234567891112131415161718192021222324252627282930313233343536373839404142434446474849505152535455575859606162636465666769727476777879808182858687909293949596979899
取消回复
…

文章评论

  • 叶子Lv 1

    你好,刚接触,代码下载了,请问一下,如何测试 :han:

    WindowsChrome 90.0.4430.93 中国-上海市
    2021年5月28日
    回复
    • 李锋镝Lv 5

      @叶子 yaml文件中有配置,修改对应的配置,就可以将请求转发到配置的接口

      WindowsChrome 90.0.4430.72 中国-北京市
      2021年5月28日
      回复
  • 贺龙Lv 2

    你好!朋友!

    WindowsChrome 90.0.4430.72 中国-北京市
    2021年5月7日
    回复
    • 李锋镝管理

      @贺龙 :haha: 欢迎新朋友~

      WindowsChrome 90.0.4430.72 中国-北京市
      2021年5月7日
      回复
      • 贺龙Lv 2

        @李锋镝 看了你的文章,下了你的git代码,学到了很多!顶你!

        WindowsChrome 90.0.4430.72 中国-北京市
        2021年5月12日
        回复
        • 李锋镝管理

          @贺龙 哈哈~很荣幸能给你提供帮助,希望我们都能早日财务自由,哈哈~~

          WindowsChrome 90.0.4430.72 中国-北京市
          2021年5月12日
          回复
  • 尘世难逢开口笑,菊花须插满头归。

    那年今日(07月05日)

    • 1982年:意大利足球运动员阿尔贝托·吉拉迪诺出生
    • 1893年:《辞海》出版的主编舒新城出生
    • 1857年:国际妇女运动领袖克莱拉·蔡特金出生
    • 1826年:英国政治家莱佛士去世
    • 1811年:委内瑞拉独立
    • 更多历史事件
    最新 热点 随机
    最新 热点 随机
    Kratos+主题新功能预览及功能演示 SpringBoot DeferredLog 完整详解 LiteLLM 本地代理搭建 Claude-HUD 使用文档 Kratos+ —— Kratos 主题二次开发记录 译文:如何将单体应用拆解为微服务
    AI时代,个人技术博客的出路在哪里?这个域名注册整整十年了,十年时间,真快啊WordPress实现用户评论等级排行榜插件WordPress网站换了个字体,差点儿把样式换崩了做了一个WordPress文章热力图插件千万级大表新增字段实战指南:告别锁表与业务中断
    出院了~~~ 从"臃肿冗余"到"优雅简洁":那些让Java开发者顿悟的代码艺术与底层逻辑 准备入手个亚太的ECS,友友们有什么建议吗? Spring WebFlux底层原理深度剖析-从响应式流到事件循环的全链路拆解 分布式架构知识体系(超全核心知识大图) 多层嵌套map对象转扁平化map
    最近评论
    李锋镝 发布于 5 天前(06月30日) 目前是每天一换,一个星期不重样 :41:
    不凡 发布于 6 天前(06月29日) 主题配色挺好看。 :2:
    李锋镝 发布于 6 天前(06月29日) 已经更新了~
    懋和道人 发布于 6 天前(06月29日) 境外与附件不能访问,其他都是正常的,如果不正常可以通过更换ip访问。
    李锋镝 发布于 6 天前(06月29日) 403呀道长
    标签聚合
    MySQL WordPress 分布式 ElasticSearch JAVA K8s AI编程 SpringBoot 多线程 JVM AI Spring IDEA 日常 docker 架构 Redis 数据库 SQL MCP
    友情链接
    • Blogs·CN
    • Honesty
    • Mr.Sun的博客
    • 临窗旋墨
    • 哥斯拉
    • 彬红茶日记
    • 志文工作室
    • 懋和道人
    • 拾趣博客导航
    • 搬砖日记
    • 旧时繁华
    • 林羽凡
    • 瓦匠个人小站
    • 皮皮社
    • 知向前端
    • 蜗牛工作室
    • 韩小韩博客
    • 风渡言

    COPYRIGHT © 2026 lifengdi.com. ALL RIGHTS RESERVED.

    域名年龄

    Theme Kratos+ By Dylan Li

    津ICP备2024022503号-3

    京公网安备11011502039375号