ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

spring cloud gateway 解决跨域的问题

2021-12-09 13:06:01  阅读:231  来源: 互联网

标签:跨域 corsConfiguration spring CorsResponseHeaderFilter filter kv import gateway


1. 背景

随着前端三大框架的横空出世,前后端分离已经成为最流行的编程方式,在这种开发方式下衍生出了一系列的问题,比如说:跨域等,今天我们就来讨论一下跨域解决问题。

2.跨域参数的原因

当一个请求url的协议、域名、端口三者之间任意一个与当前页面那么这个请求就是跨域请求。

3.跨域解决方案

跨域解决方案最出名的有两个jsonp,同源策略

jsonp:是利用script标签绕过同源策略,获得一个类似这样的数据,jsonpcallback是页面存在的回调方法,参数就是想得到的json。
同源策略:就是告诉浏览器某些请求的url是和自己在同一台服务器上。

4. gateway 实现跨域

由于jsonp有很多局限性和缺点,我们一般通过设置同源策略来实现跨域,那么spring cloud gateway 如何实现同源策略设置?

4.1 配置 CorsWebFilter

gateway 是采用 spring webflux 作为 web框架,替换了之前的servelet, 关于webflux的简介请看外行人都能看得懂的WebFlux,错过了血亏! , webflux提供了一个
CorsWebFilter 来设置同源策略。


    @Bean
    public CorsWebFilter corsWebFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();

        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.setMaxAge(600L);

        source.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsWebFilter(source);
    }

但是我们配置了这个还远远达不到我们的要求,因为它会发生如下错误:
在这里插入图片描述
在这里插入图片描述
打开详情说明我们会惊讶的发现在response header里面出现了多个Access-Control-Allow-Credentials等相关信息。
找到了原因之后我们就需要写一个去重的过滤器。

4.2 写 CorsResponseHeaderFilter类

创建 CorsResponseHeaderFilter 需要继承 GlobalFilter 类, 关于 GlobalFilter 的详解请查看Spring Cloud Gateway(十一):全局过滤器GlobalFilter, CorsResponseHeaderFilter的代码如下:


import com.flow.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.ArrayList;

@Slf4j
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) {
        return chain.filter(exchange).then(Mono.defer(() -> {
            exchange.getResponse().beforeCommit(() -> {
                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 -> {
                            kv.setValue(new ArrayList<String>() {{
                                add(kv.getValue().get(0));
                            }});
                        });


                log.info("处理后的数据:{}", JsonUtils.objectToString(exchange.getResponse().getHeaders().entrySet()));
                return chain.filter(exchange);
            });

            return chain.filter(exchange);
        }));
    }

}

注意: webflux的response类是 ReactorServerHttpResponse,这个类是有为提交和已提交的状态,我们如果需要修改response的内容需要在未提交的状态下修改,所以我们必须要调用beforeCommit 函数来修改。

4.3 配置 CorsResponseHeaderFilter 类

    @Bean
    public CorsResponseHeaderFilter corsResponseHeaderFilter() {
        return new CorsResponseHeaderFilter();
    }

这样就大功告成了, 来看看运行效果吧
在这里插入图片描述

标签:跨域,corsConfiguration,spring,CorsResponseHeaderFilter,filter,kv,import,gateway
来源: https://blog.csdn.net/qq_21134059/article/details/121808025

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有