SpringBoot+Vue-解决跨域问题

所谓跨域:

在前后端分离的项目中,前台一个服务,后台一个服务。

前台的一个Axios请求打进来,要访问后台Tomcat服务器Restful接口

浏览器出于安全的考虑,使用 XMLHttpRequest对象发起 HTTP请求时必须遵守同源策略

在默认的情况下跨域是被禁止。

IP不同或者端口号不同就是跨域

HTML5带来了CORS协议解决跨域的问题

CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing),允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。它通过服务器增加一个特殊的Header[Access-Control-Allow-Origin]来告诉客户端跨域的限制,如果浏览器支持CORS、并且判断Origin通过的话,就会允许XMLHttpRequest发起跨域请求。

Access-Control-Allow-Origin:http://somehost.com 表示允许http://somehost.com发起跨域请求。
Access-Control-Max-Age:86400 表示在86400秒内不需要再发送预校验请求。
Access-Control-Allow-Methods: GET,POST,PUT,DELETE 表示允许跨域请求的方法。
Access-Control-Allow-Headers: content-type 表示允许跨域请求包含content-type

 第一步:建一个前台工程放在端口号为8084上(模仿独立的前台)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>Page Index</title>
</head>
<body>
<h2>COR测试</h2>
<p id="info"></p>
</body>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
    $.ajax({
        url: 'http://localhost:8089/ad/ap',
        type: "POST",
        xhrFields: {
           withCredentials: false
        },
        success: function (data) {
            $("#info").html("跨域访问成功:"+data);
        },
        error: function (data) {
            $("#info").html("跨域失败!!");
        }
    })
</script>
</html>

第二步:另建一个Restful接口放在端口号为8089上(模仿独立的后台)

@RestController
@RequestMapping("/ad")
public class TestController {

    @RequestMapping("/ap")
    public void run(HttpServletResponse response) {

       System.out.println("CRO SUCCESSFULLY");
    }
}

在不做任何的处理的情况下,前台的ajax调用后台8089的/ad/ap接口会发现如下情况

F12打开后会发现控制台已经报错

 其中报错信息里的这一句,正好对应了上文中的'它通过服务器增加一个特殊的Header[Access-Control-Allow-Origin]来告诉客户端跨域的限制'

No 'Access-Control-Allow-Origin' header is present on the requested resource.

也就是说跨域的本质是靠Http的Header头中的Access-Control-Allow-Origin来实现跨域的。

那么也就是说如果像解决跨域问题,就必定要解决Http的Header头中的Access-Control-Allow-Origin

以下的解决方案也是我抄别人的,我这里只做研究和测试。

解决方案1:response.addHeader

在response.addHeader这个方法中加入请求发送的ip+端口号

@RestController
@RequestMapping("/ad")
public class TestController {

    @RequestMapping("/ap")
    public void run(HttpServletResponse response) {
        response.addHeader("Access-Control-Allow-Origin", "http://localhost:8084");
        System.out.println("CO SUCCESSFULLY");
    }
}

此时可以成功跨域,在打开F12此时可以发现ResponseHeaders里面Access-Control-Allow-Origin已经生效了

解决方案2:Spring框架的原生注解@CrossOrigin

@RestController
@CrossOrigin("http://localhost:8084")
@RequestMapping("/ad")
public class TestController {

    @RequestMapping("/ap")
    public void run(HttpServletResponse response) {
//        response.addHeader("Access-Control-Allow-Origin", "http://localhost:8084");
        System.out.println("CO SUCCESSFULLY");
    }
}

这种方式也同样成功

 

解决方案3: @Configration+@Bean实现自动配置重写WebMvcConfigurer

跨域的信息都封装成WebMvcConfigurer这个对象利用Spring的自动装配原理加载进去

@Configuration
public class CorsConfig {
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            //重写父类提供的跨域请求处理的接口
            public void addCorsMappings(CorsRegistry registry) {
                //添加映射路径
                registry.addMapping("/**")
                    //放行哪些原始域
                    .allowedOrigins("*")
                    //是否发送Cookie信息
                    .allowCredentials(true)
                    //放行哪些原始域(请求方式)
                    .allowedMethods("GET","POST", "PUT", "DELETE")
                    //放行哪些原始域(头部信息)
                    .allowedHeaders("*")
                    //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
                    .exposedHeaders("Header1", "Header2");
            }
        };
    }
}

这种方式同样可以实现跨域

 解决方案4:放回新的CorsFilter

@Configuration
public class CorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        //1.添加CORS配置信息
        CorsConfiguration config = new CorsConfiguration();
        //放行哪些原始域
        config.addAllowedOrigin("*");
        //是否发送Cookie信息
        config.setAllowCredentials(true);
        //放行哪些原始域(请求方式)
        config.addAllowedMethod("*");
        //放行哪些原始域(头部信息)
        config.addAllowedHeader("*");
        //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
        config.addExposedHeader("head1");

        //2.添加映射路径
        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
        configSource.registerCorsConfiguration("/**", config);

        //3.返回新的CorsFilter.
        return new CorsFilter(configSource);
    }
}

 这种方式同样可以实现跨域

 解决方案 1 2是可以针对单个接口进行设置

 解决方案 3 4是可以全局接口进行设置

-------------------------------------------------------------------------------------------------------------------------------

到这里还没有完.......其实我之前都是做Restful接口的,直到有人问我跨域的问题,我就像从来没关注过跨域问题一样,因为我在做Restful接口时以上四种的解决方案我从来没做过,但我的项目还是前后端分离,最后还上线了。

我也自己检讨了一下自己,问了自己两个问题

1为什么自己从来没关注过跨域问题。

2为什么我SpringBoot后端明明什么也没设置,一样实现了跨域。

结合百度和之前的代码

我总结了一下原因:不是没做跨域处理,而是没在后台做跨域处理,在VUE做的跨域处理

于是我用VUE-Cli脚手架生成了一个VUE的项目

模仿之前的工程写了一个demo.vue

  <template>
<el-form ref='form' :model='form' label-width="80px">
	<el-form-item label='用户名'>
	 <el-input v-model="form.name" placeholder="请输入内容" ></el-input>
	</el-form-item>
	<el-form-item label='密码'>
	 <el-input v-model="form.password" placeholder="请输入内容"></el-input>
	</el-form-item>
  <el-form-item label="角色">
    <el-radio-group v-model="form.role">
      <el-radio label="用户"></el-radio>
      <el-radio label="管理者"></el-radio>
    </el-radio-group>
  </el-form-item>
    <el-form-item>
     <el-button type="primary" @click="on">Submit</el-button>
	</el-form-item>
</el-form>
</template>
<script>
import { productInfoApi } from "@/common/api";
import axios from "axios";
export default {
data(){
  return{
       form:{
         name: 'yurenxu',
         password: '1121',
         role: ''
           }
        }

    } ,
  methods:{
    on(){
      axios.post('/api/ad/ap',this.form).then(rep=>{
      rep.data
      })
    }
    }
}
</script>
<style scoped>
</style>

 在Config的包下index.js下,原来是用一个代理方式来实现

查了一下代理方式的原理:将域名发送给本地的服务器(启动vue项目的服务,localhost:8080),再由本地的服务器去请求真正的服务器

module.exports = {
  dev: {
    // Paths
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: {
      '/api': {
        target:"http://localhost:8089/",
        chunkOrigins: true,// 允许跨域
        pathRewrite:{
             '^/api': '' // 路径重写,使用"/api"代替target.
        }
      }
    }
}
}

测试一下,同样可以跨域成功

 在F12的时候可以看到进来的请求是

但实际请求地址为:http://localhost:8084/ad/ap,因为在vue中重写了api实际为http://localhost:8084 

这也是我为什么做的RustfulAPI时候什么也没设置,但依然实现了跨域。

当然这,这并不能成为自己认识不足的借口,学无止境,每一次的问题,就应该有一个解决办法。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值