前后端分离项目解决跨域问题

前言

作为前后端分离的项目,经常会遇到跨域问题,例如下面这样的
在这里插入图片描述
因为使用vue启动的前端项目运行在 9528端口,而后台项目运行在8601端口,这样因为不同端口的原因就造成了跨域请求。

同时及时在相同的域名或者端口上,也有可能会遇到跨域问题,例如下面这个
在这里插入图片描述
这是是因为在请求图片的时候遇到的一个跨域问题,但是这个图片只有在使用nginx静态代理到服务器上的图片时才会遇到,如果使用的是七牛云图片则不会出现问题。问题具体的场景是在图片裁剪的时候出现的。
在这里插入图片描述
点击裁剪后,无法正常的显示图片
在这里插入图片描述

关于跨域

跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求

比如,站点 http://domain-a.com 的某 HTML 页面通过 的 src 请求 http://domain-b.com/image.jpg。网络上的许多页面都会加载来自不同域的CSS样式表,图像和脚本等资源。

出于安全原因,浏览器限制从脚本内发起的跨源HTTP请求。 例如,XMLHttpRequest和Fetch API遵循同源策略。 这意味着使用这些API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源,除非响应报文包含了正确CORS响应头。

Spring 中对 CORS 规则的校验,都是通过委托给 DefaultCorsProcessor实现的。

DefaultCorsProcessor 处理过程如下:

  • 判断依据是 Header中是否包含 Origin。如果包含则说明为 CORS请求,转到 2;否则,说明不是 CORS 请求,不作任何处理。
  • 判断 response 的 Header 是否已经包含 Access-Control-Allow-Origin,如果包含,证明已经被处理过了, 转到 3,否则不再处理。
  • 判断是否同源,如果是则转交给负责该请求的类处理
    是否配置了 CORS 规则,如果没有配置,且是预检请求,则拒绝该请求,如果没有配置,且不是预检请求,则交给负责该请求的类处理。如果配置了,则对该请求进行校验。
    校验就是根据 CorsConfiguration 这个类的配置进行判断:
    判断 origin 是否合法
    判断 method 是否合法
    判断 header是否合法
    如果全部合法,则在 response header中添加响应的字段,并交给负责该请求的类处理,如果不合法,则拒绝该请求

前后端跨域问题

方法一

针对第一个问题,我们可以在我们后台的启动类上添加下面这个Bean即可,


    @Bean

    public WebMvcConfigurer corsConfigurer() {

        return new WebMvcConfigurer() {

            @Override

            public void addCorsMappings(CorsRegistry registry) {

                //配置允许跨域访问的路径

                registry.addMapping("/**/**")

                        .allowedOrigins("*")

                        .allowedMethods("*")

                        .allowedHeaders("*")

                        .allowCredentials(true)

                        .exposedHeaders("")

                        .maxAge(3600);

            }

        };

    }

方法二

或者使用下面的方法


    private CorsConfiguration buildConfig() {

        CorsConfiguration corsConfiguration = new CorsConfiguration();

        corsConfiguration.addAllowedOrigin("*");

        corsConfiguration.addAllowedHeader("*");

        corsConfiguration.addAllowedMethod("*");

        return corsConfiguration;

    }



    /**

     * 跨域过滤器

     *

     * @return

     */

    @Bean

    public CorsFilter corsFilter() {

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

        source.registerCorsConfiguration("/**", buildConfig());

        return new CorsFilter(source);

    }

注意

在这里我推荐使用的是第一种方法,最开始我使用的是第二个方法来解决跨域的问题的,但是后面有了一个新的需求时,也就是我的token需要在将要过期的时候刷新,然后我需要在token刷新后,后台将token传递到前台,我后端代码是这样编写的


            if(StringUtils.isNotEmpty(onlineAdmin) && !jwtHelper.isExpiration(token, audience.getBase64Secret())) {

                /**

                 * 得到过期时间

                 */

                Date expirationDate = jwtHelper.getExpiration(token, audience.getBase64Secret());

                long nowMillis = System.currentTimeMillis();

                Date nowDate = new Date(nowMillis);

                // 得到两个日期相差的间隔,秒

                Integer second = DateUtils.getSecondByTwoDay(expirationDate, nowDate);

                // 如果小于5分钟,那么更新过期时间

                if(second < refreshSecond) {

                    // 生成一个新的Token

                    String newToken = tokenHead + jwtHelper.refreshToken(token, audience.getBase64Secret(), expiresSecond * 1000);

                    // 生成新的token,发送到客户端

                    CookieUtils.setCookie("Admin-Token", newToken, expiresSecond.intValue());

                    // 重新更新Redis中的过期时间

                    redisUtil.setEx(RedisConf.LOGIN_TOKEN_KEY + RedisConf.SEGMENTATION + newToken, onlineAdmin, expiresSecond, TimeUnit.SECONDS);

                }

            } else {

                chain.doFilter(request, response);

                return;

            }

这个时候就需要我在axios中进行如下配置,即添加 withCredentials=true 这样才能够让后端的token传递到前端


// 创建axios实例

const service = axios.create({

  baseURL: '', // api 的 base_url

  withCredentials: true, //允许后台的cookie传递到前端

  timeout: 100000 // 请求超时时间

})



关于 withCredentials

XMLHttpRequest 的 withCredentials 属性

默认值为false。在获取同域资源时设置 withCredentials 没有影响。

true:在跨域请求时,会携带用户凭证

false:在跨域请求时,不会携带用户凭证;返回的 response 里也会忽略 cookie

但是如果我使用的是第二种解决跨域的方法,那么在我将这个值设置成true的时候,将无法进行登录,还是出现如下的问题,最后通过查阅资料,发现设置了第一种解决跨域的方法,能成功将token传递到前端,并且存入到Application 的 Cookie中。
在这里插入图片描述

在这里插入图片描述

图片跨域问题

关于图片跨域问题的解决方法,主要是需要在nginx配置允许跨域,因为蘑菇博客的图片是存储在本地服务器中的,然后通过nginx进行静态资源映射过去的,从而出现上面的图片跨域问题。

解决方法,就是需要在nginx.conf文件中进行修改,添加如下内容


        add_header Access-Control-Allow-Origin *;

        add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';

        add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,lang,access-token';

        if ($request_method = 'OPTIONS') {

         return 204;

        }



例如,我在 demoadmin.moguit.cn 和 demopicture.moguit.cn的nginx中的配置
在这里插入图片描述
添加完成后,我们重启nginx,然后等待一段时间后,即可正常显示图片了~
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值