spring-cloud-gateway 解决cors跨域和重复header头的两种解决方案

 

配置项解决冲突

# 这一段前面的配置是处理跨域的,本文处理重复header的请看最后一条配置
spring.cloud.gateway.globalcors.cors-configurations.[/**].allow-credentials=true
spring.cloud.gateway.globalcors.cors-configurations.[/**].allowed-headers[0]=*
spring.cloud.gateway.globalcors.cors-configurations.[/**].allowed-methods[0]=*
spring.cloud.gateway.globalcors.cors-configurations.[/**].allowed-origins[0]=*
spring.cloud.gateway.globalcors.cors-configurations.[/**].max-age=1800
# 相同header多个值时的处理方式,三种规则可选(RETAIN_FIRST|RETAIN_UNIQUE|RETAIN_LAST)
spring.cloud.gateway.default-filters[0]=DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials, RETAIN_FIRST


代码解决重复header头的问题和跨域问题:

package com.xxxxxx.komoe.mng.api.filter;

import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.core.Ordered;
import reactor.core.publisher.Mono;
import com.xxxxxx.komoe.mng.api.utils.JacksonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import java.util.*;


@Slf4j
@Component("corsResponseHeaderFilter")
public class CorsResponseHeaderFilter implements GlobalFilter, Ordered {

    @Override
    public int getOrder() {
        // 指定此过滤器位于NettyWriteResponseFilter之后
        // 即待处理完响应体后接着处理响应头
        return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER + 1;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        try {
            Set<Map.Entry<String, List<String>>> beforeHeaders = exchange.getResponse().getHeaders().entrySet();
            log.info("处理前的header头={}", JacksonUtils.parseToJson(beforeHeaders));
            return chain.filter(exchange).then(
                    Mono.defer(() -> {
                        exchange.getResponse().getHeaders().entrySet().stream()
                                .filter(kv -> (kv.getValue() != null && kv.getValue().size() > 1))
                                /*.filter(kv -> (kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)|| kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)))*/
                                .forEach(
                                        kv -> {
                                            // 重新填入对应值
                                            log.info("key={},value={}", JacksonUtils.parseToJson(kv.getKey()), JacksonUtils.parseToJson(kv.getValue()));
                                            kv.setValue(new ArrayList<String>() {{
                                                add(kv.getValue().get(0));
                                            }});
                                        });
                        Set<Map.Entry<String, List<String>>> entries2 = exchange.getResponse().getHeaders().entrySet();
                        String s1 = JacksonUtils.parseToJson(entries2);
                        log.info("处理完毕的header头={}", s1);
                        return chain.filter(exchange);
                    }));
        } catch (Exception e) {
            log.error("去除重复请求头error,{},{}",e);
        } finally {

        }
        return chain.filter(exchange);
    }

}

 

package com.xxxxxxxx.komoe.mng.api.filter;

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;

@Configuration
public class CorsConfiguration {

    private static final String ALLOWED_HEADERS = "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN,token,username,client,Origin,No-Cache,X-Requested-With,If-Modified-Since,Pragma,Last-Modified,Cache-Control,Expires,Access-Control-Allow-Credentials,Biligame-Request-Id,request-game-id,request-game-base-id,request-account-domain";
    private static final String ALLOWED_METHODS = "*";
    private static final String ALLOWED_METHODS_TEST = "GET,POST,OPTIONS";

    private static final String ALLOWED_ORIGIN = "*";
    private static final String ALLOWED_EXPOSE = "*";
    private static final String MAX_AGE = "3600";



    @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();
                //todo  如果后续需要由我们来处理get请求的跨域问题,则将上面的代码处理即可....
                /*//  配置为*
                headers.set("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
                headers.add("Access-Control-Allow-Credentials", "true");
                //   配置为*
                headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
                //   "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN,token,username,client,
                //   Origin,No-Cache,X-Requested-With,If-Modified-Since,Pragma,Last-Modified,Cache-Control,Expires";
                headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
                //   配置为
                headers.add("Access-Control-Expose-Headers", ALLOWED_EXPOSE);
                //   配置为 3600
                //第一次是浏览器使用OPTIONS方法发起一个预检请求  每1800秒才会有一次
                headers.add("Access-Control-Max-Age", MAX_AGE);*/

                if (request.getMethod() == HttpMethod.OPTIONS) {
                    //  配置为*
                    headers.set("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
                    headers.add("Access-Control-Allow-Credentials", "true");
                    //   配置为*
                    headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
                    headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
                    headers.add("Access-Control-Expose-Headers", ALLOWED_EXPOSE);
                    /**Access-Control-Max-Age  限制下次的时间
                    *第一次是浏览器使用OPTIONS方法发起一个预检请求
                    *浏览器会限制从脚本发起的跨域HTTP请求(比如异步请求GET, POST, PUT, DELETE, OPTIONS等等),所以浏览器会向所请求的服务器发起两次请求,
                    *第一次是浏览器使用OPTIONS方法发起一个预检请求,第二次才是真正的异步请求,第一次的预检请求获知服务器是否允许该跨域请求
                    *如果允许,才发起第二次真实的请求;如果不允许,则拦截第二次请求。
                    * */
                    headers.add("Access-Control-Max-Age", MAX_AGE);
                    /**header头 (206, "Partial Content")*/
                    response.setStatusCode(HttpStatus.PARTIAL_CONTENT);
                    return Mono.empty();
                }
            }
            return chain.filter(ctx);
        };
    }
}

 

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring Cloud网关跨域配置可以通过以下步骤来完成。 首先,在Spring Cloud网关项目的配置文件中进行相关配置。可以通过在配置文件中设置以下属性来允许跨域访问: ```yml spring: cloud: gateway: globalcors: corsConfigurations: '[/**]': allowedOrigins: "*" allowedMethods: - GET - POST allowCredentials: true ``` 上述配置中,allowedOrigins设置为"*"表示允许来自所有域的请求。 其次,可以在编写路由规则的时候,设置cors参数来针对特定的请求路径进行跨域配置。例如: ```yml spring: cloud: gateway: routes: - id: service-route uri: http://localhost:8081 predicates: - Path=/service/** filters: - RewritePath=/service/(?<remaining>.*), /\$\{remaining} - RewritePath=/service/(?<remaining>.*), /\$\{remaining} metadata: response-headers: Access-Control-Allow-Origin: "*" Access-Control-Allow-Methods: "GET, POST" Access-Control-Max-Age: "3600" Access-Control-Allow-Headers: "Content-Type, x-requested-with, Authorization" ``` 在上述示例中,针对路径为/service/**的请求进行了跨域配置,允许来自任意域的请求,并设置了允许的请求方法和响应信息。 最后,还可以使用自定义的CorsWebFilter来进行更灵活的跨域配置。可以通过编写一个实现CorsConfigurationSource接口的类,并在该类中自定义cors配置,然后在WebFluxConfigurer中注册该CorsConfigurationSource实现即可。 通过以上的配置和步骤,Spring Cloud网关可以实现跨域访问的配置。这样就能够允许不同域的请求访问网关,并实现前后端的数据交互。 ### 回答2: Spring Cloud Gateway 是基于Spring WebFlux框架的一个API网关服务,用于构建微服务架构中的路由转发和过滤器链。在Spring Cloud Gateway中配置跨域请求是相对较简单的。 在Spring Cloud Gateway中可以通过添加过滤器来实现跨域请求。首先,在配置文件中添加路由配置,指定需要跨域的路径和目标服务。然后,编写一个全局的过滤器类,通过继承GlobalFilter和Ordered接口来实现全局过滤器。在过滤器中,通过CorsUtils类来判断请求是否为跨域请求,如果是,则设置跨域响应信息。 具体的步骤如下: 1. 在application.yml文件中配置路由: ```yaml spring: cloud: gateway: routes: - id: myRoute uri: http://example.com predicates: - Path=/api/** filters: - StripPrefix=1 ``` 2. 创建一个全局的过滤器类CorsFilter.java: ```java @Component public class CorsFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); if (CorsUtils.isCorsRequest(request)) { ServerHttpResponse response = exchange.getResponse(); HttpHeaders headers = response.getHeaders(); headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*"); headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "POST, GET, PUT, OPTIONS, DELETE"); headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "*"); headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "3600"); headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*"); headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); } return chain.filter(exchange); } @Override public int getOrder() { return -1; } } ``` 3. 启动应用,并访问配置的跨域接口。 通过以上步骤,我们可以简单地在Spring Cloud Gateway中配置跨域请求。在过滤器中,我们判断请求是否为跨域请求,并在响应中添加相关的跨域信息。这样,就能够实现对跨域请求的支持。 ### 回答3: Spring Cloud网关是一个基于Spring Cloud的微服务架构中的核心组件,它可以用来进行统一的请求路由、请求过滤、集中认证等功能。当我们在使用Spring Cloud网关时,可能会遇到跨域的问题,下面我将详细介绍Spring Cloud网关的跨域配置。 要配置Spring Cloud网关的跨域,我们可以在网关的配置文件中添加如下代码段: ``` spring: cloud: gateway: globalcors: cors-configurations: '[/**]': allowed-origins: '*' allowed-methods: - GET - POST - PUT - DELETE allowed-headers: '*' allow-credentials: true max-age: 1800 ``` 在这个配置中,我们使用`spring.cloud.gateway.globalcors.cors-configurations`参数指定了全局的CORS配置。`'[/**]'`表示匹配所有路径,我们也可以根据自己的需求指定一个具体的路径。`allowed-origins`指定了允许的源,可以使用`*`表示允许所有源。`allowed-methods`指定了允许的HTTP方法。`allowed-headers`指定了允许的自定义信息。`allow-credentials`表示是否允许发送cookie等身份验证信息。`max-age`表示预检请求的缓存时间。 除了全局配置外,我们还可以在GatewayFilter中对特定的路径进行跨域配置,例如: ``` @Configuration public class GatewayConfig { @Bean public RouteLocator routeLocator(RouteLocatorBuilder builder) { return builder.routes() .route(r -> r.path("/api/**") .filters(f -> f.hystrix(c -> c.setFallbackUri("/fallback"))) .uri("lb://service-a")) .build(); } @Bean public CorsWebFilter corsFilter() { return new CorsWebFilter(new UrlBasedCorsConfigurationSource()); } } ``` 在上述配置中,`routeLocator()`方法用于配置路由规则,其中`.path("/api/**")`表示匹配以`/api/`开的路径,然后使用`filters()`方法添加一些过滤器,最后使用`uri()`方法将请求转发到service-a服务。 `corsFilter()`方法用于添加CorsWebFilter,通过`UrlBasedCorsConfigurationSource`来实现对特定路径的跨域配置。 以上就是Spring Cloud网关跨域配置的一些常用方法,我们可以根据实际需求选择适合的方式来配置跨域

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值