IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> SpringCloud Gateway用法详解 -> 正文阅读

[Java知识库]SpringCloud Gateway用法详解

零、人在月球

目录

零、人在月球

一、功能简介

1、网关是一个服务:

二、Gateway 断言

1、path断言

2、Query断言

3、Method断言

4、Host断言

5、Cookie断言

6、Header断言

7、Weight 权重路由

8、After 时间路由

9、Before 时间路由

10、Between时间区间路由

11、灰度发布

三、Gateway 过滤器

1、增加header 请求头

2、新增动态header请求头

3、设置请求头 过滤器配置,修改移除请求头

4、PreserverHostHeader

5、重写response加密密码

6、response去重

7、路径带前缀 请求/get/app 其实是/prefix/get

8、配置30几 跳转到指定地址

9、修改状态码

10、转发地址

11、去掉\增加 请求路径中部分层级

12、重试过滤器

13、过滤器设置请求大小

14、spring-session

15、默认filter

四、熔断机制?

1、老熔断

2、熔断机制-新的

五、限流配置

1、增加依赖

2、配置redis:spring.redis.database:XX

3、配置keyResolver,参考类RateLimiteConfig

4、ym配置spring.cloud.gateway.routes

5、当发生限流,会向redis存储两个数据 .限流返回状态码是429

6、配置文件RateLimiteConfig.java

六、自定义谓词配置类

1、配置类UserNameCheckRoutePredicateFactory.java

2、配置项

七、自定义过滤器

1、配置类

pre配置类

post过滤器

3、配置文件

八、全局过滤器

九、网关超时配置

十、元数据 metadata

十一、gateway内置API与跨域

1、API说明:

2、打开端点配置

3、跨域请求:


一、功能简介

1、网关是一个服务:

路由:使用webflux、缓存、权重和灰度发布、随机算法

过滤器:有序

限流:内置令牌桶+Redis 整合GoogleGuava

权限

hystrix 熔断

声明周期

二、Gateway 断言

断言:predicates 多断言可以配合使用

1、path断言

predicates:

????????-Path=/mg

2、Query断言

参数值可以写正则,也可以只写参数名

predicates:

????????-Query=foo,ba.

3、Method断言

predicates:

????????-Method=get

4、Host断言

predicates:

????????-Host=mashibing.com

5、Cookie断言

predicates:

????????-Cookie=name,yiming

6、Header断言

predicates:

????????-Header=reqId,9090\d+ #正则表达式\d+ 数字

7、Weight 权重路由

- id: weight2
  uri: http://localhost:6601
  predicates:
    - Path=/api/**
    - Weight=group1,2
  filters:
    - StripPrefix=1
- id: weight8
  uri: http://localhost:6602
  predicates:
    - Path=/api/**
    - Weight=group1,8
  filters:
    - StripPrefix=1

8、After 时间路由

#After
      - id: after_route
        uri: lb://micore-test1
        predicates:
          - After=2022-02-07T17:05:00.789+08:00[Asia/Shanghai]

9、Before 时间路由

- Before=2022-02-07T17:05:00.789+08:00[Asia/Shanghai]

10、Between时间区间路由

- Between=2021-02-07T17:05:00.789+08:00[Asia/Shanghai],2022-02-07T17:05:00.789+08:00[Asia/Shanghai]

11、灰度发布

同一个请求地址,设置多个url也就是多个服务。比如M5,和MD5 两个服务,比重设置95%和5%。先升级一部分的服务,再切换另一个服务进行升级。

三、Gateway 过滤器

1、增加header 请求头

附加:代码中获取请求头 JSONView插件

spring.cloud.gateway.routes
-id: add_request_header
uri: lb://test-prod
predicates: 
    -Path= /getheader
filters:
    #增加请求头、请求参数
    -AddRequestHeader= X-Request-id, 99999
    -AddRequestHeader= X-Request-author, kevin
    -AddRequestParameter= param-id,99999
    -AddRequestParameter= param-author, kevin
    -AddResponseHeader=rep-id, 99999
    -AddResponseHeader=req-author,kevin

java代码获取header 和请求参数param 和response

@GetMapping("getHeaders")
public Map<String,String> getHeaders(HttpServletRequest request){
    Map<String,String> map =new HashMap<>();
    Enumeration<String> headerNames = request.getHeaderNames();
    while (headerNames.hasMoreElements()) {
        String name = headerNames.nextElement();
        String value = request.getHeader(name);
        map.put(name,value);
    }
    return map;
}
@GetMapping("getParameter")
public Map<String,String[]> getparam(HttpServletRequest request){
    Map<String,String[]> paramMap=request.getParameterMap();
    return paramMap;
}
@GetMapping("getResponseHeader")
public Map<String,Collection<String>> getheader3(HttpServletResponse response){
    response.addHeader("req-id","123456");
    response.addHeader("req-id","1234567");
    response.addHeader("rep-url","/42?user=ford&paddwd=omg!what&flag=true");
    Map<String,Collection<String>>map=new HashMap<>();
    Collection<String> headerNames=response.getHeaderNames();
    for(String name:headerNames){
        Collection<String> headers=response.getHeaders(name);
        map.put(name,headers);
    }
    return map;
}

2、新增动态header请求头

predicates:
    -Path= /getheader/{seq}
filters:
    -AddRequestHeader= X-Request-id, 99999-{seq}
    -AddRequestHeader= X-Request-author, kevin-{seq}
    -AddRequestParameter= param-id,99999-{seq}
    -AddRequestParameter= param-author, kevin-{seq}
    -AddResponseHeader=rep-id, 99999-{seq}
    -AddResponseHeader=req-author,kevin-{seq}

方法:@GetMapping("getHeader/{param}")

3、设置请求头 过滤器配置,修改移除请求头

#设置请求头,没有则新增,有则修改
-SetRequestHeader=X-Request-id,9999
#移除请求头、请求参数
-RemoveRequestHeader= X-Request-id
-RemoveRequestParameter=X-Request
-RemoveRequestParameter=X-Request-author
#先从header取from-Header,如果有则赋值给to-Header,如果没from-Header则无效果
-MapRequestHeader=from-Header,to-Header

4、PreserverHostHeader

#默认开启,在gateway转发请求前把原始请求的host头部带上,转发给目的服务

-PreserverHostHeader

5、重写response加密密码

#例如: req-url=/42?user=ford&passwd=omg!what&flag=true 经过下面配置替换为/42?user=ford&passwd=***&flag=true

-RewriteResponseHeader=req-url,passwd=[^&]+,passwd=***

6、response去重

RETAIN_FIRST保留第一个

RETAIN_LAST保留最后一个

RETAIN_FIRST RETAIN_UNIQUE 保留唯一

-DedupeResponseHeader= req-id,RETAIN_FIRST

7、路径带前缀 请求/get/app 其实是/prefix/get

-PrefixPath= /prefix

8、配置30几 跳转到指定地址

#300 Multiple多种选择,请求的资源可能包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端选择

#301 Moved Permanently永久移动,请求的资源已被永久移动新位置,返回信息会包含URI,浏览器会自动定向到新地址,以后请求应该用新的URI代替

#302 Found 临时移动,与301类似,资源临时被移动,客户端应该继续使用原URI

#303See Other查看其它地址,与301类似。使用GET和POST请求查看

#304未修改,所请求资源未修改,服务器返回此状态吗时,不会返回任何资源

#305Use proxy 使用代理,所请求资源必须通过代理

#306 Unused 已经废弃的HTTP状态码

#307 Temporary Redirect 临时重定向,与302类似,使用GET请求重定向

? -RedirectTo=302,http://www.baidu.com 

-RedirectTo=301,http://www.taobao.com
?

9、修改状态码

#修改状态码,可以org.springframework.http.HttpStatus枚举,也可以直接写状态码

-SetStatus=NOT_FOUND
-SetStatus=404

10、转发地址

#访问/api/getheader 实际访问:/getheader,转发的目的地址必须写 / 否则会出错

-RewritePath=/api/getheader, /getheader

#http://192.168.31.80:8801/www/get/user/12123 实际访问:/prefix/get/user/12123

#http://192.168.31.80:8801/www/getheader 实际访问:/prefix/getheader

-RewritePath=/www/(?/?.*), /prefix/$\{segment}

转发例子2 例如请求/profix/get/user/12123 实际请求是 /get/user

predicates:
    -Path=/prefix/{var1}/{var2}/{var3}
filter:
    -SetPath=/{var1}/{var2}

11、去掉\增加 请求路径中部分层级

#请求/api/get/123 实际请求/get/123

-StripPrefix=1 从前往后去掉一些路径

#请求/get/123 实际请求/prefix/get/123

-PrefixPath=/prefix 增加前缀路径

12、重试过滤器

predicates:
    -Path=/testRetry
filters:
    - name:  Retry  #过滤器名称
      args:
        retries: 3 #重试次数
        series: #org.springframework.http.HttpStatus.Series 枚举 什么类型状态码进行重试
            -SERVER_ERROR
            -CLIENT_ERROR
        statuses:#org.springframework.http.HttpStatus枚举值,什么状态码重试
            -BAD_GATEWAY
            -METHOD_NOT_ALLOWED
        methods: #什么类型方法重试
            -GET
            -POST
        exception: #什么异常进行重试
            -java.io.IOException
        backoff:#重试时间间隔
            firstBackoff: 10ms
            maxBackoff: 50ms
            factor: 2
            basedOnPreviousValue: false

13、过滤器设置请求大小

filters:
    -name: RequestSize #过滤器名称
     args:   #控制请求的大小,超过则返回413.请求最大默认5000000 约5M
        maxSize:1000  #1KB

14、spring-session

filters:
#只有当集成Spring Session才会将session放到Redis,来实现共享Session功能,如果项目继承了Spring Session中的Spring Security框架。如果希望安全验证信息可以转发到远程应用,那么这个配置是必须的
    - SaveSession

15、默认filter

spring.cloud.gateway.default-filters:
    -AddRequestHeader=X-Request-Default, Gateway

四、熔断机制?

1、老熔断

①增加依赖包:org.springframework.cloud:spring-cloud-starter-netflix-hystrix

②默认熔断配置

spring.cloud.gateway
default-filters:
    -name: Hystrix #设置默认熔断器
     args:
        name: fallback1 #熔断器名字,随便起
        fallbackUrl: forward:/fallbackHysrix  //发生熔断后跳转的地址
#设置hystrix断路器超时时间
hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMillliseconds:2000  #2秒

该地址:需要在gateway项目中新增一个controller? com.longze.controller.FallbackController

@RestController
public class FallbackController {
    @RequestMapping("/fallbackHysrix")
    public String fallbackHysrix(){
        return "fallbackHystrix error";
    }
    @RequestMapping("/fallbackCircuitBreaker")
    public String fallbackCircuitBreaker(){
        return "fallbackCircuitBreaker error";
    }
}

③单独配置熔断器

spring.cloud.gateway.routes
filters:
    -name: Hystrix #设置熔断器
     args:
        name: fallbackcmd #熔断器名字,无所谓
        fallbackUri: forward:/fallbackHysrix #熔断之后跳转,本项目或其他项目配置
#熔断项目在其他项目中
-id: Hystrix-fallback
uri: http://localhost:9100
predicates:
    -Path: /fallbackHysrix

2、熔断机制-新的

①增加依赖包:org.springframework.cloud:spring-cloud-starter-circuitbreaker-reactor-resilience4j

和 org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j

②#开启resilience4j熔断

spring.cloud.circuitbreaker.resilience4j.enabled: true

③配置熔断 和Hystrix很相似

spring.cloud.gateway.routes

filters:
    -name: CircuitBreaker #设置熔断器
     args:
        name: testCircuitBreaker #熔断器名字,无所谓
        fallbackUri: forward:/fallbackCircuitBreaker #熔断之后跳转,本项目或其他项目配置

五、限流配置

1、增加依赖

org.springframework.boot:spring-boot-starter-data-redis-reactive

2、配置redis:spring.redis.database:XX

/host/ port/ /password

3、配置keyResolver,参考类RateLimiteConfig

4、ym配置spring.cloud.gateway.routes

-id: rate-limit-demo
uri: lb://mima-cloud-producer
predicates:
    -Path=/rate/**
filters:
    -name: RequestRateLimiter
     args:
        #令牌桶每秒平均速率,允许用户每秒处理多少个请求
        redis-rate-limiter.replenishRate:1
        #令牌桶的容量,允许在1s内完成的最大请求数
        redis-rate-limiter.burstCapacity:2
        #使用Spel表达式从Spring容器中获取Bean对象,查看RateLimiteConfig实现类中同名方法
        key-resolver: "#{@pathKeyResolver}"
        #key-resolver: "#{@ipKeyResolver}"
        #key-resolver: "#{@userKeyResolver}"

5、当发生限流,会向redis存储两个数据 .限流返回状态码是429

request_rate_limiter.{key}.timestamp

request_rate_limiter.{key}.tokens

timestamp:存储的是当前时间秒数,也就是System.currentTimeMillis()/1000

tokens:存储的当前这秒钟对应的可用令牌数

6、配置文件RateLimiteConfig.java

package com.pig4cloud.pig.demo.controller;

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * @Auther: fengqx
 * @Date: 2022/1/2 - 01 -02 - 22:36
 * @Description: 限流配置
 * @Version: 1.0
 */
@Configuration
public class RateLimiteConfig{

    //ip限流  1s 100次
    //userId限流 1s 100次
    //路径限流
    @Bean
    @Primary  #如果不使用 @Primary 注解,项目启动会报错
    public KeyResolver pathKeyResolver(){
        //写法1
//        return exchange-> Mono.just(
//                exchange.getRequest()
//                .getPath()
//                .toString()
//        );
        //写法2
        return new KeyResolver(){
            @Override
            public Mono<String> resolve(ServerWebExchange exchange){
                return Mono.just(exchange.getRequest()
                .getPath()
                .toString());
            }
        };
    }
    //根据请求IP限流
    @Bean
    public KeyResolver ipKeyResolver(){
        return exchange -> Mono.just(
                exchange.getRequest()
                .getRemoteAddress()
                .getHostName()
        );
    }
    //根据userid限流
    @Bean
    public KeyResolver userKeyResolver(){
        return exchange -> Mono.just(
                exchange.getRequest()
                .getQueryParams()
                .getFirst("userId")
        );
    }
}

六、自定义谓词配置类

可以保存数据库,存储。

1、配置类UserNameCheckRoutePredicateFactory.java

package com.pig4cloud.pig.demo.util;

import com.mysql.cj.util.StringUtils;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;

import javax.validation.constraints.NotEmpty;
import java.util.function.Predicate;

/**
 * @Auther: fengqx
 * @Date: 2022/1/2 - 01 -02 - 23:20
 * @Description: 自定义谓词,请求入参包含指定userName
 * @Version: 1.0
 */
@Component
public class UserNameCheckRoutePredicateFactory extends AbstractRoutePredicateFactory<UserNameCheckRoutePredicateFactory.Config> {

    public UserNameCheckRoutePredicateFactory(){
        super(Config.class);
    }
    @Override
    public Predicate<ServerWebExchange> apply(UserNameCheckRoutePredicateFactory.Config config) {
        //写法1
        return new Predicate<ServerWebExchange>() {
            @Override
            public boolean test(ServerWebExchange exchange) {
                String userName = exchange.getRequest().getQueryParams().getFirst("userName");
                if(StringUtils.isNullOrEmpty(userName)){
                    return false;
                }
                //检查请求参数中userName是否与配置的数据相同,如果相同则允许访问,否则不允许访问
                if(userName.equals(config.getName())){
                    return true;
                }
                return false;
            }
        };
    }

    @Validated
    public static class Config{
        @NotEmpty
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}

2、配置项

spring.cloud.gateway
routes:
    -id: Auth_route
     uri: lb://mima-cloud-producer
     order:1
     predicates:
        -Path= /**
        #name配置为UserNameCheckRoutePredicateFactory自定义谓词配置类前缀UserNameCheck, 只有     访问http://192.168.1.10:8081/getheader?userName=Kevin,否则为404
        #必须写在userName请求参数,并且值为kevin
        -name=UserNameCheck
         args:
            name: kevin

七、自定义过滤器

1、配置类

pre配置类

package com.pig4cloud.pig.demo.util;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.NotEmpty;

/**
 * @Auther: fengqx
 * @Date: 2022/1/3 - 01 -03 - 10:48
 * @Description: 自定义过滤器 -Pre过滤器
 * @Version: 1.0
 */
@Component
public class MyAddRequestHeaderGatewayFilterFactory extends AbstractGatewayFilterFactory<MyAddRequestHeaderGatewayFilterFactory.Config> {
    public MyAddRequestHeaderGatewayFilterFactory(){super(Config.class);}

    @Override
    public GatewayFilter apply(Config config){
        //写法一
//        return new GatewayFilter() {
//            @Override
//            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//                System.out.println("MyAddRequestHeaderGatewayFilterFactory.apply is run...");
//                //exchange.getRequest().mutate() //目的是转化为装饰类,否则request为只读的,不能操作
//                //header方法用来设置header的值
//                ServerHttpRequest request = exchange.getRequest().mutate().header(config.getName(),config.getValue()).build();
//                //将request包裹继续向下传递
//                return chain.filter(exchange.mutate().request(request).build());
//            }
//        }
        return (exchange, chain) -> {
            System.out.println("MyAddRequestHeaderGatewayFilterFactory.apply is run...");
            //exchange.getRequest().mutate() //目的是转化为装饰类,否则request为只读的,不能操作
            //header方法用来设置header的值
            ServerHttpRequest request=exchange.getRequest().mutate().header(config.getName(),config.getValue()).build();
            return chain.filter(exchange.mutate().request(request).build());
             //response可以直接写
//            exchange.getResponse().getHeaders().set(config.getName(),config.getValue());
//            return chain.filter(exchange);
        };
    }

    @Validated
    public static class Config{
        @NotEmpty
        private String name;
        @NotEmpty
        private String value;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }
    }
}

post过滤器

@Component
public class PostLogGatewayFilterFactory extends AbstractGatewayFilterFactory {
    @Override
    public GatewayFilter apply(Object config){
        return (exchange, chain) -> {
            return chain.filter(exchange).then(Mono.fromRunnable(()-> {
                System.out.println("PostLogGatewayFilterFactory is run...");
            }));
        };
    }
}

3、配置文件

spring.cloud.gateway.routes
-id: MyFilter
uri: lb://mima-cloud
order: 1
predicates:
    -Path=/**
filters:
    -name: MyAddRequestHeader  #Pre过滤器
     args:
        name: req-kevin-header
        value: req-yin.hl
    -name: PostLogGateway  #Post过滤器
效果,所有请求增加一个header

八、全局过滤器

配置文件不需要配置,只需要增加GlobalFilterConfig 类,即可执行到全局过滤

package com.pig4cloud.pig.demo.util;

import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import reactor.core.publisher.Mono;

/**
 * @Auther: fengqx
 * @Date: 2022/1/3 - 01 -03 - 21:23
 * @Description: 全局过滤器
 * @Version: 1.0
 */
@Configuration
public class GlobalFilterConfig {
    //order 越小,越先执行
    @Bean
    @Order(-1)
    public GlobalFilter globalFilter1(){
        return (exchange, chain) -> {
            System.out.println("pro filter globalFilter1...");
            return chain.filter(exchange).then(Mono.fromRunnable(()->{
                System.out.println("post filter globalFilter1...");
            }));
        };
    }
    @Bean
    @Order(1)
    public GlobalFilter globalFilter2(){
        return (exchange, chain) -> {
            System.out.println("pro filter globalFilter2...");
            return chain.filter(exchange).then(Mono.fromRunnable(()->{
                System.out.println("post filter globalFilter2...");
            }));
        };
    }
}

应答顺序为:pro filter globalFilter1...

pro filter globalFilter2...

post filter globalFilter2...

post filter globalFilter1...

九、网关超时配置

spring.cloud.gateway.httpclient.connect-timeout=1000 #连接超时 毫秒

spring.cloud.gateway.httpclient.response-timeout=5s #应答超时 java.time.Duration http状态码504

十、元数据 metadata

十一、gateway内置API与跨域

1、API说明:

/actuator/gateway/routes/{id} ,method=[DELETE] 删除单个路由

/actuator/gateway/routes/{id},method=[POST] 新增单个路由

/actuator/gateway/routes/{id},method=[GET] 查看单个路由

/actuator/gateway/routes ,method=[GET] 查看路由列表

/actuator/gateway/refresh,method=[POST] 路由刷新

/actuator/gateway/globalfilters,method=[GET]获取全局过滤器列表

/actuator/gateway/routefilters,method=[GET] 路由过滤器工厂列表

2、打开端点配置

management.endpoint.gateway.enabled=true

3、跨域请求:

配置文件-直接引用即可

package com.pig4cloud.pig.demo.util;
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.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
/**
 * @Auther: fengqx
 * @Date: 2022/1/3 - 01 -03 - 22:03
 * @Description: 跨域配置
 * http://vvv.mekebin.com/123  ajax-> http://vvv.mekebin.com/123/test 不跨域
 * http://vvv.mekebin.com/123  ajax-> http://def.mekebin.com/123/test 跨域
 * http://vvv.mekebin.com:8801/123  ajax-> http://vvv.mekebin.com:9901/123/test 跨域
 * http://vvv.mekebin.com/123  ajax-> https://vvv.mekebin.com/123/test 跨域
 * @Version: 1.0
 */
@Configuration
public class CorsConfig {
    private static final String MAX_AGE="18000L";
 
    @Bean
    public WebFilter corsFilter(){
        return (ServerWebExchange ctx, WebFilterChain chain)->{
            System.out.println("corsFilter...  run");
            ServerHttpRequest request = ctx.getRequest();
            if(!CorsUtils.isCorsRequest(request)){
                return chain.filter(ctx);
            }
            HttpHeaders requestHeaders=request.getHeaders();
            ServerHttpResponse response = ctx.getResponse();
            HttpMethod requestMethod= requestHeaders.getAccessControlRequestMethod();
            HttpHeaders headers=response.getHeaders();
            headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestHeaders.getOrigin());
            headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlAllowHeaders());
            if(requestMethod!=null){
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS,requestMethod.name());
            }
            //携带cookie
            headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
            headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS,"*");
            headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);
            if(request.getMethod() == HttpMethod.OPTIONS){
                response.setStatusCode(HttpStatus.OK);
                return Mono.empty();
            }
            return chain.filter(ctx);
        };
    }
}

荆轲刺秦王!

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-01-04 13:16:53  更:2022-01-04 13:18:05 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 9:03:34-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码