SpringBoot + Vue前后端分离开发的跨域问题

简介: 解决SpringBoot + Vue前后端分离开发的跨域问题

SpringBoot + Vue前后端分离开发的跨域问题

文章目录

  • SpringBoot + Vue前后端分离开发的跨域问题
  • 一个因跨域问题报错的例子
  • 跨域问题与浏览器的同源策略
  • 如何解决跨域问题
  • 后端来解决
  • 前端来解决

一个因跨域问题报错的例子

  我们以一个简单的springboot + vue前后端分离小例子来引入跨域问题,我们要从前端输入一个字符串,然后通过ajax发送请求将这个字符串传给后端,由后端接收并打印出来

  这个例子十分简单,我们直接上代码:

  后端:

@RestController
@RequestMapping("/data")
public class GetAndPrintData {
    @PostMapping("/put/string")
    public void getAndPrintString(@RequestBody StringData stringData) {
        System.out.println(stringData.getStringData());
    }
}
@Data
public class StringData {
    private String stringData;
}

  前端:

<template>
  <div>
    <el-form ref="dataForm" :model="dataForm" label-width="80px" class="login-box">
      <h3 class="login-title">来传输数据</h3>
      <el-form-item label="字符串数据" prop="stringData">
        <el-input type="text" placeholder="请输入字符串信息" v-model="dataForm.stringData"/>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" v-on:click="onSubmit()">传输数据</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
export default {
  name: "CrosTest",
  data() {
    return {
      dataForm: {
        stringData: ''
      },
    }
  },
  methods: {
    onSubmit() {
      axios({
        method: 'POST',
        url: 'http://localhost:8181/data/put/string',
        data: this.dataForm
      })
    }
  }
}
</script>
<style scoped>
</style>

  这里要注意的点是前端传的JSON中的key要和后端实体类中的属性对应,后端实体类属性为stringData,前端传的JSON中的key也要为stringData,若为stringdata,则对应不上,后端将接收不到相应数据

  我们启动前后端后,输入字符串并提交,发现前端报错,后端没有接收到数据

e71e69b06e6d46daaeab5f9074ee6ead.png

  来看看具体的报错信息:

Access to XMLHttpRequest at 'http://localhost:8181/data/put/string' from origin 'http://localhost:8081' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

  它说我们的http请求被CORS policy给blocked了,那么什么是CORS policy呢?接下来我们就来谈谈跨域问题

跨域问题与浏览器的同源策略

  什么是跨域呢?浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域。在我们的前后端分离开发中,首先,前后端端口就一定不同,也就是说,前端发请求到后端一定是跨域。与跨域相对的概念就是同源,两个页面地址中的协议,域名,端口号一致,则表示同源。

  浏览器采用了同源策略。同源策略保证了以下3点:

  1、无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB

  2、无法接触非同源网页的 DOM(HTML DOM 定义了用于 HTML 的一系列标准的对象,以及访问和处理 HTML 文档的标准方法)

  3、无法成功向非同源地址发送 AJAX 请求(可以发送,但浏览器会拒绝接受响应)

  为什么浏览器要采取同源策略呢?主要是为了保证安全,如果没有同源限制存在,浏览器中的cookie等其他数据可以任意读取,不同域下DOM任意操作,ajax任意请求的话,如果浏览了恶意网站那么就会泄漏这些隐私数据,恶意程序也能给别的网站疯狂进行ajax请求。

  我们之前的例子就是因为向非同源地址发送了ajax请求,被浏览器的同源策略拒绝了

如何解决跨域问题

后端来解决

  既然无法成功向非同源地址发送 AJAX 请求,那有没有出现什么方法来解决这个问题呢,毕竟我们是要经常发送跨域请求的。W3C制定了一个标准CORS,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

  CORS需要浏览器和服务器同时支持,浏览器这端完全不用担心,目前的浏览器一般没有不支持的。整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。这就是后端的任务了。

  这种方法是跨源 AJAX 请求的根本解决方法。

  因此,我们只要让后端实现CORS接口就好了,CORS接口的具体细节可以参考:跨域资源共享 CORS 详解

  我们使用@Configuration注解创建一个配置类,该配置类需实现WebMvcConfigurer接口,这里提供两种方式来进行配置:

  方法1:配置类里面使用@Bean标注在构造器方法上用以注入一个CorsFilter对象,此方法适用于配置类需要进行很多配置的场合,推荐使用,下面上代码:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class Configurer implements WebMvcConfigurer {
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);   // 可选字段,表示是否允许发送Cookie,true表示允许
        config.addAllowedOrigin("http://localhost:8081");   // 必填字段,"*"表示接受任意域名的请求
        config.addAllowedHeader("*");   // 可选字段,允许CORS请求额外发送的头信息字段
        config.addAllowedMethod("*");   // 必填字段,允许CORS请求使用的HTTP方法, "*"表示全部方法
        config.setMaxAge(3600L);    // 可选字段,用来指定预检请求的有效期,单位为秒。在有效期间,不用发出另一条预检请求
        source.registerCorsConfiguration("/**", config);    // 必填字段,"/**"表示请求路径是多级,"/*/*"表示请求路径是两级
        return new CorsFilter(source);
    }
}

  方法2:配置类重写addCorsMappings方法,若该配置类只负责CORS配置,则可使用此方法:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class Configurer implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")  // 必填字段,"/**"表示请求路径是多级,"/*/*"表示请求路径是两级
                .allowedOriginPatterns("http://localhost:8081")     // 必填字段,"*"表示接受任意域名的请求
                .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")  // 必填字段,允许CORS请求使用的HTTP方法, "*"表示全部方法
                .allowCredentials(true)     // 可选字段,表示是否允许发送Cookie,true表示允许
                .maxAge(3600)   // 可选字段,用来指定预检请求的有效期,单位为秒。在有效期间,不用发出另一条预检请求
                .allowedHeaders("*");   // 可选字段,允许CORS请求额外发送的头信息字段
    }
}

  这里对上述代码解释一下,Origin字段在CORS中用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。我们在配置中设置了allowCredentials(true),表示允许发送Cookie,此时allowedOriginPatterns就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器域名下的Cookie,这也是为了安全考虑,因此我们将允许的OriginPatterns设为前端域名http://localhost:8081。同时由于Cookie的收发前后端都要参与,必须在AJAX请求中打开withCredentials属性,我们要在vue项目的main.js中加上这样一句配置:axios.defaults.withCredentials=true;

11.png

  不加上这句配置,即使服务器同意发送Cookie,浏览器也不会发送。或者,服务器要求设置Cookie,浏览器也不会处理。

  下面我们来测试一下:

22.png

33.png

  成功解决了跨域问题

前端来解决

  前端来解决跨域问题有几种方法:

  1、使用WebSocket通信协议,这里不详解。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。

  2、中间代理服务转发:在前端服务和后端接口服务之间架设一个中间代理服务,它的地址保持和后端服务器一致,这样,我们就可以通过中间服务做接口转发,在开发环境下解决跨域问题。我们需要vue.config.js中配置代理服务,通过这个代理服务发送请求,由于代理服务和后端端口号相同,这样就不存在跨域的问题了,代码如下:

'use strict'
module.exports = {
    dev: {
        host: 'localhost',
        port: 8081,
        autoOpenBrowser: false,
        overlay: {
            warnings: false,
            errors: true
        },
        // 代理配置
        proxy: {
            // 如果请求地址以/data打头,就触发代理机制
            // http://localhost:8081/data/put/string -> http://localhost:8181/data/put/string
            '/data': {
                target: 'http://localhost:8181',//后端接口地址
                changeOrigin: true,//是否允许更改Origin
                pathRewrite: {
                    '^/data': '/data',//重写,
                }
            }
        },
    },
}
目录
相关文章
|
6天前
|
前端开发 安全 Java
基于springboot+vue开发的会议预约管理系统
一个完整的会议预约管理系统,包含前端用户界面、管理后台和后端API服务。 ### 后端 - **框架**: Spring Boot 2.7.18 - **数据库**: MySQL 5.6+ - **ORM**: MyBatis Plus 3.5.3.1 - **安全**: Spring Security + JWT - **Java版本**: Java 11 ### 前端 - **框架**: Vue 3.3.4 - **UI组件**: Element Plus 2.3.8 - **构建工具**: Vite 4.4.5 - **状态管理**: Pinia 2.1.6 - **HTTP客户端
71 4
基于springboot+vue开发的会议预约管理系统
|
4月前
|
JavaScript 前端开发 Java
制造业ERP源码,工厂ERP管理系统,前端框架:Vue,后端框架:SpringBoot
这是一套基于SpringBoot+Vue技术栈开发的ERP企业管理系统,采用Java语言与vscode工具。系统涵盖采购/销售、出入库、生产、品质管理等功能,整合客户与供应商数据,支持在线协同和业务全流程管控。同时提供主数据管理、权限控制、工作流审批、报表自定义及打印、在线报表开发和自定义表单功能,助力企业实现高效自动化管理,并通过UniAPP实现移动端支持,满足多场景应用需求。
431 1
|
1月前
|
前端开发 JavaScript Java
基于springboot+vue开发的校园食堂评价系统【源码+sql+可运行】【50809】
本系统基于SpringBoot与Vue3开发,实现校园食堂评价功能。前台支持用户注册登录、食堂浏览、菜品查看及评价发布;后台提供食堂、菜品与评价管理模块,支持权限控制与数据维护。技术栈涵盖SpringBoot、MyBatisPlus、Vue3、ElementUI等,适配响应式布局,提供完整源码与数据库脚本,可直接运行部署。
73 0
基于springboot+vue开发的校园食堂评价系统【源码+sql+可运行】【50809】
|
4月前
|
供应链 JavaScript BI
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发
这是一款专为小微企业打造的 SaaS ERP 管理系统,基于 SpringBoot+Vue+ElementUI+UniAPP 技术栈开发,帮助企业轻松上云。系统覆盖进销存、采购、销售、生产、财务、品质、OA 办公及 CRM 等核心功能,业务流程清晰且操作简便。支持二次开发与商用,提供自定义界面、审批流配置及灵活报表设计,助力企业高效管理与数字化转型。
436 2
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发
|
2月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
730 0
|
6月前
|
前端开发 Java 数据库
微服务——SpringBoot使用归纳——Spring Boot集成Thymeleaf模板引擎——Thymeleaf 介绍
本课介绍Spring Boot集成Thymeleaf模板引擎。Thymeleaf是一款现代服务器端Java模板引擎,支持Web和独立环境,可实现自然模板开发,便于团队协作。与传统JSP不同,Thymeleaf模板可以直接在浏览器中打开,方便前端人员查看静态原型。通过在HTML标签中添加扩展属性(如`th:text`),Thymeleaf能够在服务运行时动态替换内容,展示数据库中的数据,同时兼容静态页面展示,为开发带来灵活性和便利性。
307 0
|
2月前
|
缓存 JSON 前端开发
第07课:Spring Boot集成Thymeleaf模板引擎
第07课:Spring Boot集成Thymeleaf模板引擎
379 0
第07课:Spring Boot集成Thymeleaf模板引擎
|
6月前
|
XML Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于 xml 的整合
本教程介绍了基于XML的MyBatis整合方式。首先在`application.yml`中配置XML路径,如`classpath:mapper/*.xml`,然后创建`UserMapper.xml`文件定义SQL映射,包括`resultMap`和查询语句。通过设置`namespace`关联Mapper接口,实现如`getUserByName`的方法。Controller层调用Service完成测试,访问`/getUserByName/{name}`即可返回用户信息。为简化Mapper扫描,推荐在Spring Boot启动类用`@MapperScan`注解指定包路径避免逐个添加`@Mapper`
283 0
|
6月前
|
Java 测试技术 微服务
微服务——SpringBoot使用归纳——Spring Boot中的项目属性配置——少量配置信息的情形
本课主要讲解Spring Boot项目中的属性配置方法。在实际开发中,测试与生产环境的配置往往不同,因此不应将配置信息硬编码在代码中,而应使用配置文件管理,如`application.yml`。例如,在微服务架构下,可通过配置文件设置调用其他服务的地址(如订单服务端口8002),并利用`@Value`注解在代码中读取这些配置值。这种方式使项目更灵活,便于后续修改和维护。
92 0
|
6月前
|
SQL Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— application.yml 中对日志的配置
在 Spring Boot 项目中,`application.yml` 文件用于配置日志。通过 `logging.config` 指定日志配置文件(如 `logback.xml`),实现日志详细设置。`logging.level` 可定义包的日志输出级别,例如将 `com.itcodai.course03.dao` 包设为 `trace` 级别,便于开发时查看 SQL 操作。日志级别从高到低为 ERROR、WARN、INFO、DEBUG,生产环境建议调整为较高级别以减少日志量。本课程采用 yml 格式,因其层次清晰,但需注意格式要求。
608 0