vue学习系列:JS跨域问题的解决

场景

最近,使用vue+element-ui开发前端界面,在前端界面和后端后台进行联调的时候,发现接口不通,提示报错:

no 'access-control-allow-origin' header is present on the requested resource

这个报错其实是JS跨域问题,具体情况,请各位读者继续往下看。

环境

软件版本
JDK8
spring-boot2.1.8.RELEASE
vue/cli4.3.1

正文

一、介绍

1、根由

跨域问题其实就是浏览器的同源策略所导致的。以下是从《MDN-浏览器的同源策略》摘抄下来的:

同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。 ——摘自 《MDN-浏览器的同源策略

2、同源的定义

如果两个 URL 的 protocol、port (如果有指定的话)和 host 都相同的话,则这两个 URL 是同源。这个方案也被称为“协议/主机/端口元组”,或者直接是 “元组”。(“元组” 是指一组项目构成的整体,双重/三重/四重/五重/等的通用形式)。 ——摘自 《MDN-浏览器的同源策略

从上面的定义可以知道,满足同源的条件主要有以下几点:

  1. 协议相同
  2. 域名相同
  3. 端口相同
    只要满足这三点,才算是同源。

3、限制同源的缘由

  1. 限制不同源的请求
    设置了同源策略,当一个网站访问非同源域的网址的时候,默认不会将cookie这些信息附加上去,避免了信息的泄露。
  2. 限制DOM操作
    当我们登陆恶意网址的时候,同源策略会限制对应的js操作document来获取其他网址的cookie等敏感信息

4、为什么需要跨域

当我们访问跨域请求的时候,像ajax请求的时候,请求发出来了,但是响应在浏览器端就会被拦截住。像现在都提倡前后端分离,所以目前博主的项目是前后端分离的,前端使用vue+elemenet-ui来编写,后端使用spring-boot来搭建项目。而这两个项目肯定是使用各自的域名和端口的。从同源策略的定义来看,我们浏览器访问肯定是会受限的。所以需要解决跨域问题。

二、解决方法

因为本项目是使用vuespring-boot来搭建的,所以这里的解决方法主要是针对这两个的。如果有其他需要,请查看文章尾部的参考链接。而说到这里,我们就要介绍一下 CORS了。

1、CORS简介

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

2、前端设置代理

因为我们是使用vue来搭建项目,vue-clivue官方提供的脚手架,为熟悉vue减少操作的复杂性。我们可以在vue.config.js里面进行设置,如下:

module.exports = {
  devServer: {
    port: 8001,
    proxy: {
      "/api": {
        target: "http://localhost:8081"
      }
    }
  }
};
缺陷

只能在开发环境使用,生产环境无法使用。

3、后台设置过滤器

博主的项目是spring-boot项目,所以可以设置过滤器,浏览器进行预检请求的时候,返回对应的参数,让其可以进行跨域请求。

i、设置环境变量

application.yml文件写入以下内容:

spring:
  cors:
    allowOrigin:
    allowMethods: POST,PUT,GET,OPTIONS,DELETE,PATCH
    allowHeaders: Authorization,Content-Type
    allowCredentials: false
    maxAge: 3600
ii、设置 config类

创建CorsFilterProperties类,定义以下内容:

@Data
@ConfigurationProperties(prefix = "spring.cors")
public class CorsFilterProperties {
    private String allowOrigin;
    private String allowMethods;
    private String allowHeaders;
    private Boolean allowCredentials;
    private Long maxAge;
}
iii、设置filter类

创建CorsFilterConfig类,写入以下内容:

@Configuration
@EnableConfigurationProperties({CorsFilterProperties.class})
public class CorsFilterConfig {
    @Autowired
    private CorsFilterProperties corsFilterProperties;

    @Bean
    @Order
    public FilterRegistrationBean registerCorsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(corsFilterProperties.getAllowCredentials());
        if (StringUtils.isBlank(corsFilterProperties.getAllowOrigin())) {
            config.addAllowedOrigin("*");
        } else {
            String[] arr = corsFilterProperties.getAllowOrigin().split(",");
            for (String origin : arr) {
                config.addAllowedOrigin(origin);
            }
        }
        if (corsFilterProperties.getAllowHeaders().equals("*")) {
            config.addAllowedHeader("*");
        } else {
            String[] headers = corsFilterProperties.getAllowHeaders().split(",");
            for (String header : headers) {
                if (StringUtils.isNotBlank(header)) {
                    config.addAllowedHeader(header);
                }
            }
        }
        if (corsFilterProperties.getAllowMethods().equals("*")) {
            config.addAllowedMethod("*");
        } else {
            String[] methods = corsFilterProperties.getAllowMethods().split(",");
            for (String method : methods) {
                if (StringUtils.isNotBlank(method)) {
                    config.addAllowedMethod(method);
                }
            }
        }
        config.setMaxAge(corsFilterProperties.getMaxAge());
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
        bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return bean;
    }
}

结果

通过在后端后台添加了cors的支持,使得前后端交互顺利执行。

总结

在实际开发中,遇到问题并追溯问题发生的缘由,不断解决并理解,对于个人能力的提升是很有好处的。

参考链接

彻底理解浏览器的跨域
Spring 里那么多种 CORS 的配置方式,到底有什么区别
10 种跨域解决方案(附终极方案)

随缘求赞

如果我的文章对大家产生了帮忙,可以在文章底部点个赞或者收藏;
如果有好的讨论,可以留言;
如果想继续查看我以后的文章,可以左上角点击关注;
可以扫描以下二维码,关注我的公众号:枫夜之求索阁,查看我最新的分享!
在这里插入图片描述
拜拜

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

枫夜求索阁

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

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

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

打赏作者

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

抵扣说明:

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

余额充值