7.Cloud-GateWay

0.概述

https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/

1.入门配置

  1.1 POM

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

<!-- nacos -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

  1.2 YML

server:
  port: 9527
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: payment-route
          uri: lb://cloud-order-service
          predicates:
            - Path=/v2/order/**
          filters:
            - StripPrefix=1
    nacos:
      discovery:
        server-addr: 192.168.2.18:8848
    inetutils:
      ignored-interfaces: ['VMware.*']

  1.3 主启动类

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

  1.4 测试

localhost:9527/v2/order/

2.Predicate的使用

pring:
  cloud:
    gateway:
      routes:
      - id: before_route
        uri: lb://cloud-order-service
        predicates:
      # 在某个时间之前的请求才会被转发到 http://localhost:8001,
          - Before=2017-01-20T17:42:47.789+08:00[Asia/Shanghai]
      # 在某个时间之后的请求才会被转发
      #   - After=2017-01-20T17:42:47.789+08:00[Asia/Shanghai]
      # 在某个时间段之间的才会被转发
      #   - Between=2017-01-20T17:42:47.789+08:00[Asia/Shanghai], 2017-01-21T17:42:47.789+08:00[Asia/Shanghai]
 
      # 名为chocolate的表单或者满足正则ch.p的表单才会被匹配到进行请求转发
      #   - Cookie=chocolate, ch.p
    
      # 携带参数X-Request-Id或者满足\d+的请求头才会匹配
      #   - Header=X-Request-Id, \d+
 
      # 按Host主机名匹配
      #   - Host=qiying.com:8080
	
      # 按请求方法进行匹配,只有GET方法才会匹配
      #   - Method=GET
      # 按请求路径进行匹配
      #   - Path=/app/{path}
	
        filters:
      # 在请求路径前加上自定义的路径
      #   - PrefixPath=/app
      # 重写请求路径
      # 访问localhost:8080/test, 请求会转发到localhost:8001/app/test
      #   - RewritePath=/test, /app/test
      #   - RewritePath=(?<oldPath>^/), /app$\{oldPath}
      # 通过模板设置路径
      #   - SetPath=/app/{path}

3.Filter的使用

  3.1 自定义全局过滤器

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.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Date;

@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        log.info("*********come in MyLogGateWayFilter: "+new Date());

        String name = exchange.getRequest().getQueryParams().getFirst("username");
        if(StringUtils.isEmpty(name))
        {
            log.info("*****用户名为Null 非法用户,(┬_┬)");
            exchange.getResponse().setRawStatusCode(HttpStatus.NOT_ACCEPTABLE.value());
            return exchange.getResponse().setComplete();
        }

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

  3.2 令牌桶算法限流

    1) YML配置

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:     
      routes:
        - id: cloud-order-service
          uri: lb://cloud-order-service
          predicates:
            - Path=/v2/**
            - After=2024-02-17T10:41:00.000+08:00[Asia/Shanghai]
          filters:
            - name: StripPrefix
              args:
                parts: 1
            - name: RequestRateLimiter
              args:
                keyResolver: '#{@myKeyResolver}'
               redis-rate-limiter.replenishRate: 1 #生产令牌速度,每秒多少个
               redis-rate-limiter.burstCapacity: 5 #令牌桶容量
    nacos:
      discovery:
        server-addr: 192.168.2.18:8848
    inetutils:
      ignored-interfaces: ['VMware.*']
  redis:
    host: 192.168.2.18
    password: 123456

    2) 创建MyKeyResolver类

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class MyKeyResolver implements KeyResolver {

    @Override
    public Mono<String> resolve(ServerWebExchange exchange) {

        String address = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
        return Mono.just(address);
    }
}

    3) request_rate_limiter.lua

local tokens_key = KEYS[1]
local timestamp_key = KEYS[2]
--redis.log(redis.LOG_WARNING, "tokens_key " .. tokens_key)

local rate = tonumber(ARGV[1])
local capacity = tonumber(ARGV[2])
local now = tonumber(ARGV[3])
local requested = tonumber(ARGV[4])

local fill_time = capacity/rate
local ttl = math.floor(fill_time*2)

--redis.log(redis.LOG_WARNING, "rate " .. ARGV[1])
--redis.log(redis.LOG_WARNING, "capacity " .. ARGV[2])
--redis.log(redis.LOG_WARNING, "now " .. ARGV[3])
--redis.log(redis.LOG_WARNING, "requested " .. ARGV[4])
--redis.log(redis.LOG_WARNING, "filltime " .. fill_time)
--redis.log(redis.LOG_WARNING, "ttl " .. ttl)

local last_tokens = tonumber(redis.call("get", tokens_key))
if last_tokens == nil then
  last_tokens = capacity
end
--redis.log(redis.LOG_WARNING, "last_tokens " .. last_tokens)

local last_refreshed = tonumber(redis.call("get", timestamp_key))
if last_refreshed == nil then
  last_refreshed = 0
end
--redis.log(redis.LOG_WARNING, "last_refreshed " .. last_refreshed)

local delta = math.max(0, now-last_refreshed)
local filled_tokens = math.min(capacity, last_tokens+(delta*rate))
local allowed = filled_tokens >= requested
local new_tokens = filled_tokens
local allowed_num = 0
if allowed then
  new_tokens = filled_tokens - requested
  allowed_num = 1
end

--redis.log(redis.LOG_WARNING, "delta " .. delta)
--redis.log(redis.LOG_WARNING, "filled_tokens " .. filled_tokens)
--redis.log(redis.LOG_WARNING, "allowed_num " .. allowed_num)
--redis.log(redis.LOG_WARNING, "new_tokens " .. new_tokens)

redis.call("setex", tokens_key, ttl, new_tokens)
redis.call("setex", timestamp_key, ttl, now)

return { allowed_num, new_tokens }

    4) 如果请求每秒超过5个,将无法访问, 执行的类,RedisRateLimiter.isAllowed

  3.3 自定义断言过滤器

    1) 创建过滤器

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;
 
@Component
@Slf4j
public class XXGatewayFilterFactory extends AbstractGatewayFilterFactory<XXGatewayFilterFactory.Config> {

    public XXGatewayFilterFactory()
    {
        super(Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {

        return Arrays.asList("path");
    }

    @Override
    public GatewayFilter apply(Config config) {

        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

                log.info("xx-GatewayFilter-filter");
                return chain.filter(exchange);
            }
        };
    }

    public static class Config
    {
        public String getPath() {
            return path;
        }

        public void setPath(String path) {
            this.path = path;
        }

        private String path;
    }
}

    2) YML

spring:
  cloud:
    gateway:       
      routes:
        - id: cloud-order-service
          uri: lb://cloud-order-service
          predicates:
            - Path=/v2/**
            - After=2024-02-17T10:41:00.000+08:00[Asia/Shanghai]
          filters: 
            - name: XX

  3.4 

4.跨域

  4.1 普通跨域

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowedHeaders: "*"
            allowedOrigins: "*"
            allowedMethods: "*"

  4.2 诺依跨域

package com.ruoyi.gateway.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import com.ruoyi.gateway.handler.ValidateCodeHandler;
import reactor.core.publisher.Mono;

/**
 * 路由配置信息
 * 
 * @author ruoyi
 */
@Configuration
public class RouterFunctionConfiguration
{
    /**
     * 这里为支持的请求头,如果有自定义的header字段请自己添加
     */
    private static final String ALLOWED_HEADERS = "X-Requested-With, Content-Type, Authorization, credential, X-XSRF-TOKEN, token, username, client, request-origion";
    private static final String ALLOWED_METHODS = "GET,POST,PUT,DELETE,OPTIONS,HEAD";
    private static final String ALLOWED_ORIGIN = "*";
    private static final String ALLOWED_EXPOSE = "*";
    private static final String MAX_AGE = "18000L";
    
    @Autowired
    private ValidateCodeHandler validateCodeHandler;

    @SuppressWarnings("rawtypes")
    @Bean
    public RouterFunction routerFunction()
    {
        return RouterFunctions.route(
                RequestPredicates.GET("/code").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
                validateCodeHandler);
    }

    /**
     * 跨域配置
     */
    @Bean
    public WebFilter corsFilter()
    {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            if (CorsUtils.isCorsRequest(request))
            {
                ServerHttpResponse response = ctx.getResponse();
                HttpHeaders headers = response.getHeaders();
                headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
                headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
                headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
                headers.add("Access-Control-Expose-Headers", ALLOWED_EXPOSE);
                headers.add("Access-Control-Max-Age", MAX_AGE);
                headers.add("Access-Control-Allow-Credentials", "true");
                if (request.getMethod() == HttpMethod.OPTIONS)
                {
                    response.setStatusCode(HttpStatus.OK);
                    return Mono.empty();
                }
            }
            return chain.filter(ctx);
        };
    }
}

<think>好的,我现在要解决用户关于如何配置Spring Cloud Gateway的HTTP客户端响应超时时间的问题。首先,我需要回忆一下相关的配置方法。记得Spring Cloud Gateway的配置主要是在application.yml或者application.properties文件中进行的。用户提到的是httpclient的response-timeout,这可能涉及到全局配置和每个路由的单独配置。 首先,我需要确认全局的响应超时配置参数。根据之前的经验,全局设置通常在spring.cloud.gateway.httpclient下面。比如,connect-timeout是连接超时,response-timeout是响应超时。用户提供的引用中也提到了response-timeout: 5s,这应该是一个例子。所以全局配置应该是这样的: spring: cloud: gateway: httpclient: connect-timeout: 1000 response-timeout: 5s 接下来,用户可能还想知道如何为每个路由单独设置超时时间。这时候需要用到路由的metadata配置。每个路由可以配置自己的超时参数,比如response-timeout和connect-timeout。例如: routes: - id: example_route uri: http://example.org predicates: - Path=/example/** metadata: response-timeout: 2000 connect-timeout: 500 不过,我需要确认metadata中的参数名称是否正确,是否是response-timeout和connect-timeout。可能需要查阅官方文档来验证这一点,确保不会给出错误的配置。记得在路由级别的配置中,单位是毫秒,而全局配置中的response-timeout用了5s,这可能需要统一单位或者确认是否支持不同的时间单位。 另外,可能需要提醒用户注意优先级的问题,即路由级别的配置会覆盖全局配置。例如,如果某个路由设置了response-timeout,那么该路由会使用自己的值,而其他没有设置的路由则使用全局的配置。 还需要注意时间单位的转换是否正确,比如5s在YAML中会被自动转换为毫秒吗?或者是否需要用Duration格式,比如PT5S?可能需要指出正确的格式,避免用户配置错误。例如,Spring Boot通常支持的时间单位包括ms(毫秒)、s(秒)、m(分钟)等,所以在全局配置中使用5s是正确的,而在路由的metadata中可能需要以毫秒为单位,比如2000表示2秒。 最后,可能需要给出一个完整的示例,帮助用户更好地理解如何配置。同时,提醒用户测试配置是否生效,可以通过日志或者实际请求来验证超时设置是否正确。如果有常见的错误配置,比如单位错误或者拼写错误,也应该提及,帮助用户避免这些问题。</think>关于Spring Cloud Gateway的HTTP客户端响应超时时间配置,支持全局和路由级别的设置,具体方法如下: ### 一、全局配置 在`application.yml`中通过`spring.cloud.gateway.httpclient.response-timeout`定义全局响应超时: ```yaml spring: cloud: gateway: httpclient: connect-timeout: 1000 # 连接超时(毫秒) response-timeout: 5s # 响应超时(支持时间单位) ``` 此配置对所有路由生效,响应超时单位支持`ms`(毫秒)、`s`(秒)等[^1]。 ### 二、单路由配置 通过路由元数据`metadata`覆盖全局配置: ```yaml routes: - id: custom_route uri: lb://service-name predicates: - Path=/api/** metadata: response-timeout: 3000 # 单位:毫秒 connect-timeout: 500 # 单位:毫秒 ``` 路由级别配置优先级高于全局配置。 ### 三、注意事项 1. 全局响应超时默认值为`null`(无限制) 2. 路由元数据配置必须使用毫秒数值 3. 超时触发会返回`504 Gateway Timeout` 4. WebFlux客户端需要配置`reactor-netty.http.client`相关参数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wang_peng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值