SpringBoot+Vue前后端跨域问题

随着分布式微服务的兴起,越来越多的公司在开发web项目的时候选择前后端分离的模式开发,前后端分开部署,使得分工更加明确,彻底解放了前端。

我们知道,http请求都是无状态,现在比较流行的都是jwt的形式处理无状态的请求,在请求头上带上认证参数(token等),前后端分离有好处,也有坏处,第一次开发前后端分离项目的人,肯定会遇到前端请求跨域的问题,这个怎么处理呢?在说处理方案前,有必要说明一下为什么会跨域和什么是跨域?

一、为什么会跨域?

出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的 javascript 脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)

二、什么是跨域?

当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域

当前页面url(即浏览器地址)被请求页面url(即后端接口地址)是否跨域原因
https://www.site.com/https://www.site.com/index.html同源(协议、域名、端口号相同)
https://www.site.com/http://www.site.com/index.html协议不同(https/http)
https://www.site.com/https://www.baidu.com/主域名不同(site/baidu)
https://www.site.com/https://layui.site.com/子域名不同(www/layui)
https://www.site.com:8080/https://www.site.com:8081/端口不同(8080/8081)

三、实现跨域访问

两种方面来解决

  • 前端解决(不是根本解决方案,打包后还是得由后端解决)
  • 后端解决
  • 代理服务器

3.1 前端代理访问

在vue的开发环境中跨域,通过代理的方式来实现,类似于nginx。

比如以下范例,访问 csdn 的测试接口api。

// config/index.js

module.exports = {
  dev: {
    // Paths
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: {
      '/api': {
        // 真实接口域名
        target: 'https://www.youkuaiyun.com',
        // 开启代理
        changeOrigin: true,
        pathRewrite: {
          // 重写请求地址,即将字符串^/api替换成你想要的字符串,拼接到target
          '^/api': '/api'
        }
      },
      '/v1': {
        target: 'https://suggest-follow-api-ms.juejin.im',
        changeOrigin: true,
        pathRewrite: {
          '^/v1': '/v1'
        }
      }
    },
  },

}

代码中的请求方式

method: {
  ajaxFun() {
    var url = '/api/articles?type=more&category=home&shown_offset=1524276761019196&first_view=false';
    this.$axios.get(url)
      .then(res => {
        this.articles = res.data.articles;
        console.log(res);
      })
  }
}

通过 npm run dev 之后,访问完这个接口,在控制台中显示的地址是 http://localhost:8080/api/articles?type=more&category=home&shown_offset=1524276761019196&first_view=false
相当于 https://www.youkuaiyun.com/api/articles?type=more&category=home&shown_offset=1524276761019196&first_view=false

这就实现了开发环境下的跨域请求。但我们打包上线:用 npm run build 打包成dist文件。发到线上后,还是得再次解决跨域。

3.2 后端CORS实现跨域访问

授权方式

  • 方式1:注册新的CorsFilter
  • 方式2:重写WebMvcConfigurer
  • 方式3:使用注解(@CrossOrigin)
  • 方式4:手工设置响应头(HttpServletResponse )

注:CorsFilter / WebMvcConfigurer / @CrossOrigin 需要SpringMVC 4.2 以上的版本才支持,对应SpringBoot 1.3 版本以上都支持这些CORS特性。不过,使用SpringMVC4.2 以下版本的小伙伴也不用慌,直接使用方式4通过手工添加响应头来授权CORS跨域访问也是可以的。附:在SpringBoot 1.2.8 + SpringMVC 4.1.9 亲测成功。

注:方式1和方式2属于全局CORS配置,方式3和方式4属于局部CORS配置。如果使用了局部跨域是会覆盖全局跨域的规则,所以可以通过@CrossOrigin注解来进行细粒度更高的跨域资源控制。

3.2.1 注册CorsFilter(全局跨域)

Spring框架还提供了一个 CorsFilter 。在这种情况下,您可以按如下方式在 SpringBoot 应用程序中声明过滤器。

在任意配置类,返回一个新的CorsFilter Bean,并添加映射路径和具体的CORS配置信息。

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

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

        //3.返回新的CorsFilter.
        return new CorsFilter(configSource);
    }
}
3.2.2 重写WebMvcConfigurer(全局跨域)

类似于使用过滤器,可以使用Spring MVC声明,并与细粒度配置结合使用。缺省情况下,允许所有源和方法。

在任意配置类,返回一个新的WebMvcConfigurer Bean,并重写其提供的跨域请求处理的接口,目的是添加映射路径和具体的CORS配置信息。

为整个应用程序启用 CORS 非常简单,例如:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	public void addCorsMappings(CorsRegistry registry) {
		registry.addMapping("/**");
	}
}

如果您使用的是 Spring Boot,建议只声明 Bean 如下:WebMvcConfigurer

@Configuration
public class GlobalCorsConfig {
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            //重写父类提供的跨域请求处理的接口
            public void addCorsMappings(CorsRegistry registry) {
                //添加映射路径
                registry.addMapping("/**");
            }
        };
    }
}

您可以轻松更改任何属性,也可以仅将此 CORS 配置应用于特定的路径模式:

@Override
//重写父类提供的跨域请求处理的接口
public void addCorsMappings(CorsRegistry registry) {
    //添加映射路径
    registry.addMapping("/**")
            //放行哪些原始域
            //.allowedOrigins("*")
            .allowedOrigins("http://domain2.com")
            //是否发送Cookie信息
            .allowCredentials(true)
            //放行哪些原始域(请求方式)
            .allowedMethods("GET","POST", "PUT", "DELETE")
            //放行哪些原始域(头部信息)
            .allowedHeaders("*")
            //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
            .exposedHeaders("Header1", "Header2")
            .maxAge(3600);;
}
3.2.3 使用注解@CrossOrigin(局部跨域)

在方法上(@RequestMapping)使用注解 @CrossOrigin

@RestController
@RequestMapping("/account")
public class AccountController {    
	@RequestMapping("/hello")
    @CrossOrigin("http://localhost:8080") 
    public String index( ){
        return "Hello World";
    }
}

或者在控制器(@RestController)上使用注解 @CrossOrigin

@RestController
@RequestMapping("/account")
@CrossOrigin(origins = "http://xx-domain.com", maxAge = 3600)
public class AccountController {

    @RequestMapping("/hello")
    public String index( ){
        return "Hello World";
    }
}
3.2.4 手工设置响应头(局部跨域 )

使用 HttpServletResponse 对象添加响应头(Access-Control-Allow-Origin)来授权原始域,这里 Origin 的值也可以设置为"*" ,表示全部放行。

@RestController
@RequestMapping("/account")
public class AccountController {    
	@RequestMapping("/hello")
    @ResponseBody
    public String index(HttpServletResponse response){
        response.addHeader("Access-Control-Allow-Origin", "http://localhost:8080");
        return "Hello World";
    }
}

3.4 通过nginx 代理访问

设置nginx配置文件:

location / {
    root   /dist/;
    index  index.html;
}

location /api/ {
    proxy_pass http://xxx.xxx.xxx.xxx:8090/;
    client_max_body_size 100m; 
    client_body_buffer_size 512k;
    proxy_send_timeout 300;
    proxy_read_timeout 300;
    proxy_connect_timeout 300;			
    proxy_buffer_size 64k;
    proxy_buffers 16 64k; 
    proxy_busy_buffers_size 64k;
    proxy_temp_file_write_size 64k;			
    proxy_set_header Host $host:$server_port;  
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header REMOTE-HOST $remote_addr;			
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept";
    add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
}

四、源码和文档

源码地址:SpringBoot-Cross-Orgin

专题阅读:《SpringBoot 布道系列》

官方文档:W3C规范-CORS

Spring传统文档:SpringMVC-CORS 使用手册

推荐阅读:跨域资源共享 CORS 详解 - 阮一峰

扩展

参考博客:SpringBoot 实现前后端分离的跨域访问(CORS)

<think>好的,用户之前已经问过Java前后端如何链接的问题,现在具体问的是Spring BootVue怎么链接。我需要回顾之前的回答,看看有没有需要调整的地方。 首先,用户可能已经了解前后端分离的基本概念,现在需要更具体的步骤。之前的回答提到了RESTful API、JSON数据格式和CORS配置,这些在Spring BootVue中也是适用的,但需要更详细的操作步骤。 接下来,我需要考虑用户可能的实际应用场景。他们可能正在开始一个项目,需要从零搭建前后端环境。因此,我应该提供具体的搭建步骤,比如项目创建、接口编写、前端请求方法等。 用户可能还不太清楚如何启动前后端项目,或者如何解决问题。之前的回答提到了CORS配置,但在Spring Boot中可能有更简便的方式,比如使用注解或者配置类。需要详细说明这部分内容。 另外,前端使用Vue的话,可能需要介绍axios的使用,以及如何配置代理解决问题。尤其是在开发环境下,前端代理可以避免问题,这样用户在实际开发中会更方便。 还有,用户可能对如何整合前端后端项目部署有疑问,比如是否需要将Vue打包后的文件放到Spring Boot的静态资源中。这时候需要分开发环境和生产环境来说明,避免混淆。 需要注意检查技术细节是否正确,比如Spring Boot的版本是否影响配置方式,Vue的axios请求示例是否正确。同时,确保代码示例的语法正确,避免误导用户。 最后,确保回答结构清晰,分步骤讲解,让用户能一步步跟着操作。可能还需要补充一些常见问题的解决方法,比如端口配置、错误处理,以及安全方面的建议,比如JWT的使用。</think>以下是 **Spring Boot + Vue** 前后端链接的完整实现方案,包含关键步骤代码示例: --- ### 一、技术架构设计 - **前端**:Vue 3(组合式API) + Axios + Vue Router - **后端**:Spring Boot 3.x + Spring Data JPA + MySQL - **通信方式**:RESTful API + JSON --- ### 二、环境搭建步骤 #### 1. 后端Spring Boot) 1. **创建项目** 通过 [start.spring.io](https://start.spring.io/) 生成项目,添加依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> ``` 2. **配置数据库**(`application.properties`) ```properties spring.datasource.url=jdbc:mysql://localhost:3306/mydb spring.datasource.username=root spring.datasource.password=123456 spring.jpa.hibernate.ddl-auto=update ``` 3. **编写实体控制器** ```java @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String email; // getters & setters } @RestController @RequestMapping("/api/users") public class UserController { @Autowired private UserRepository userRepository; @GetMapping public List<User> getAllUsers() { return userRepository.findAll(); } @PostMapping public User createUser(@RequestBody User user) { return userRepository.save(user); } } ``` --- #### 2. 前端Vue) 1. **创建Vue项目** ```bash npm create vue@latest # 选择需要的配置(推荐启用Router、Pinia) ``` 2. **安装Axios** ```bash npm install axios ``` 3. **配置请求工具**(`src/utils/request.js`) ```javascript import axios from 'axios'; const service = axios.create({ baseURL: 'http://localhost:8080/api', // 后端地址 timeout: 5000 }); // 请求拦截器(可添加JWT认证) service.interceptors.request.use(config => { const token = localStorage.getItem('token'); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); export default service; ``` --- ### 三、核心连接实现 #### 1. 前端调用API(Vue组件) ```vue <script setup> import { ref, onMounted } from 'vue'; import request from '@/utils/request'; const users = ref([]); // 获取数据 const fetchUsers = async () => { try { const response = await request.get('/users'); users.value = response.data; } catch (error) { console.error('请求失败:', error); } }; // 提交数据 const submitForm = async (formData) => { await request.post('/users', formData); await fetchUsers(); // 刷新列表 }; onMounted(() => { fetchUsers(); }); </script> ``` #### 2. 解决问题(开发环境) - **方案一:Vue代理配置**(`vite.config.js`) ```javascript export default defineConfig({ server: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '') } } } }); ``` - **方案二:Spring Boot配置** ```java @Configuration public class CorsConfig { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("http://localhost:5173") // Vue开发服务器端口 .allowedMethods("*"); } }; } } ``` --- ### 四、部署联调要点 1. **前端打包** ```bash npm run build ``` - 生成`dist`目录(包含静态文件) 2. **后端集成前端资源**(Spring Boot) 将`dist`目录内容复制到`src/main/resources/static`,访问时直接运行Spring Boot应用 3. **生产环境配置** ```yaml # application-prod.yml spring: mvc: static-path-pattern: /** web: resources: static-locations: classpath:/static/ ``` --- ### 五、常见问题排查 | 问题现象 | 解决方案 | |--------------------------|-----------------------------------| | 404错误(接口找不到) | 检查后端Controller的`@RequestMapping`路径 | | 请求被拦截 | 确认CORS配置或代理是否生效 | | 数据库连接失败 | 检查MySQL服务状态及JDBC配置 | | 前端无法获取响应数据 | 使用浏览器开发者工具查看网络请求 | --- ### 六、扩展功能建议 1. **安全认证**:集成Spring Security + JWT 2. **API文档**:使用Swagger生成接口文档 3. **全局异常处理**:在后端统一处理异常响应格式 4. **文件上传**:通过MultipartFile实现文件传输 通过以上配置,Spring BootVue即可实现完整的业务数据交互。实际开发中建议使用`Postman`先验证接口可用性,再编写前端逻辑代码。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值