首页 > 技术文章 > Spring Cloud入门系列(十四)- 服务网关之Gateway

amigou 2021-10-15 08:15 原文

代码演示

新建模块: cloud-gateway9527
在这里插入图片描述
pom.xml

添加gateway的dependency

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

完整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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud201230</artifactId>
        <groupId>com.banana</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>cloud-gateway9527</artifactId>


    <dependencies>
        <!--gateway-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!--gateway也是一个微服务,也需要注册进Eureka-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--引入自定义的api通用包-->
        <dependency>
            <groupId>com.banana</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--web Gateway不需要web依赖,会报错-->
        <!--<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>-->
    </dependencies>
</project>

application.yml

server:
  port: 9527

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true  #开启注册中心路由功能,利用微服务名进行路由
        # lower-case-service-id: true   #匹配路径转小写
      routes:
        - id: payment_routh   #路由ID,唯一,建议配合服务名
          # 匹配规则: http://localhost:9527/payment/get/** 的所有uri都会跳转至 lb://cloud-payment-service/
          uri: lb://cloud-payment-service   #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**
        - id: payment_routh2
          #uri: http://localhost:8001
          uri: lb://cloud-payment-service
          predicates:
            - Path=/payment/LoadBalancer/**
            - After=2021-01-20T09:51:48.195+08:00[Asia/Shanghai]  #after route 该匹配规则自上海时间2021-01-20早上9:51:48秒后生效

eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://localhost:7001/eureka

GateWayConfig.java

package com.banana.springcloud.config;

import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 以编码的方式实现路由
 * 官网:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gatewayfilter-factories
 * @author layman
 * @date 2021/1/19
 */
@Configuration
public class GateWayConfig {

    /**
     * 配置一个ID为 first 的路由规则
     * 当访问地址:http://localhost:9527/guonei 时会自动转发到地址 http://news.baidu.com/guonei
     * @param routeLocatorBuilder
     * @return RouteLocator
     */
    @Bean
    public RouteLocator CustomerRouteLocatorFirst(RouteLocatorBuilder routeLocatorBuilder){
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
        routes.route("first",r->r.path("/guonei").uri("http://news.baidu.com/guonei")).build();
        return routes.build();
    }
    /**
     * 配置一个ID为 second 的路由规则
     * 当访问地址:http://localhost:9527/guoji 时会自动转发到地址 http://news.baidu.com/guoji
     * uri配置http://news.baidu.com/和http://news.baidu.com/guoji的效果是一样的?
     * 似乎会把path的值加到rui后面,如果没有就追加,如果有就不追加,所以path的值如果乱写就会匹配不上?
     */
    @Bean
    public RouteLocator CustomerRouteLocatorSecond(RouteLocatorBuilder routeLocatorBuilder){
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
        routes.route("second",r->r.path("/text0215").uri("http://news.baidu.com/")).build();
        return routes.build();
    }
}

MyGlobalFilter.java

package com.banana.springcloud.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;

/**
 * @author layman
 * @date 2021/1/20
 */
@Component
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered {
    /**
     * ServerWebExchange:服务网络交换器 ,存放着重要的请求-响应属性、请求实例和响应实例等等,有点像 Context上下文。
     * 通过给定的GatewayFilterChain处理Web请求并且(可选)委托给下一个{WebFilter}
     * @param exchange 当前服务器交换
     * @param chain 提供了一种委托给下一个过滤器的方法
     * @return {@code Mono<Void>} 指示请求处理何时完成
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("------------come in MyGlobalFilter----------------时间:"+ LocalDateTime.now());
        //获取请求参数中的第一个参数
        String username = exchange.getRequest().getQueryParams().getFirst("username");
        if(username == null ){
            log.info("------用户名为空,非法访问------");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }
        //放行,进入下个过滤器
        return chain.filter(exchange);
    }

    /**
     * 获取此对象的顺序值。
     * <p>值越高,优先级越低。值越低,优先级越高。
     * (在某种程度上),类似于Servlet {load on startup}值。
     * <p>相同的顺序值,优先级会变得随意
     * @return 顺序值
     * @see java.lang.Integer#MIN_VALUE = -2147483648   最大优先级
     * @see java.lang.Integer#MAX_VALUE = -2147483648   最小优先级
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

TimeUtil

package com.banana.springcloud.util;

import java.time.LocalDateTime;
import java.time.ZonedDateTime;

/**
 * 获取After断言中的时间格式
 * @author layman
 * @date 2021/1/20
 */
public class TimeUtil {
    public static void main(String[] args) {
        ZonedDateTime now = ZonedDateTime.now();
        // 2021-01-20T09:51:48.195+08:00[Asia/Shanghai]
        System.out.println(now);
        System.out.println(LocalDateTime.now());
    }
}

根据application.yml中的配置,

当访问 http://localhost:9527/payment/get/88 时,该uri都跳转至 lb://cloud-payment-service/payment/get/88

测试页面如下:
在这里插入图片描述

推荐阅读