vue2/3,Spring Boot以及生产环境跨域解决方案
vue2和vue3跨域解决方案
Vue 2 (基于 Webpack) 的跨域解决方案
1. 创建或编辑 vue.config.js
文件
Vue CLI为Webpack项目提供了简单的代理配置方式。你可以通过创建或编辑项目的根目录下的 vue.config.js
文件来设置开发服务器的代理规则:
// vue.config.js
module.exports = {
devServer: {
proxy: {
'/api': { // 代理路径前缀
target: 'http://backend.example.com', // 后端API的地址
changeOrigin: true, // 更改请求源
pathRewrite: { '^/api': '' }, // 重写路径,去掉/api前缀
secure: false, // 如果后端是HTTPS,则设置为true,默认false
logLevel: 'debug' // 设置日志级别,方便调试
}
}
}
};
2. 修改前端请求代码
确保你的前端请求都通过 /api
前缀发送,这样它们会被正确代理到后端服务器:
// 在Vue组件或API服务中
import axios from 'axios';
export function fetchDepartments() {
return axios.get('/api/depts')
.then(response => response.data)
.catch(error => console.error('There was an error!', error));
}
Vue 3 (基于 Vite) 的跨域解决方案
Vite使用了一种不同的方式来处理开发服务器的代理配置。它没有像Webpack那样内置的代理配置选项,但可以通过修改 vite.config.js
来实现相同的功能。
使用 Vite 的代理配置
1. 创建或编辑 vite.config.js
文件
你需要在 vite.config.js
中定义一个 server.proxy
属性:
// vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue()],
server: {
proxy: {
'/api': {
target: 'http://backend.example.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
},
},
});
2. 修改前端请求代码
同Vue 2一样,确保所有对后端的请求都通过 /api
前缀来发送:
// 在Vue组件或API服务中
import axios from 'axios';
export function fetchDepartments() {
return axios.get('/api/depts')
.then(response => response.data)
.catch(error => console.error('There was an error!', error));
}
Spring Boot 中的 CORS 配置详解
方法 1:使用 @CrossOrigin
注解(局部配置)
@CrossOrigin
注解是最简单的方式,适用于需要为特定控制器或方法启用CORS的情况。你可以通过在控制器类或方法上添加这个注解来实现。
局部配置示例
// src/main/java/com/example/demo/controller/MyController.java
package com.example.demo.controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.ResponseEntity;
import java.util.Arrays;
import java.util.List;
@RestController
@RequestMapping("/api/depts")
@CrossOrigin(origins = "https://example.com", maxAge = 3600) // 允许的源及缓存时间
public class MyController {
@GetMapping
public ResponseEntity<List<String>> getDepts() {
List<String> depts = Arrays.asList("HR", "Finance", "IT");
return ResponseEntity.ok(depts);
}
}
注意事项
origins
:指定允许的源。maxAge
:预检请求的结果可以被缓存的时间(以秒为单位)。allowedHeaders
:可选,指定允许的HTTP头。methods
:可选,指定允许的HTTP方法。exposedHeaders
:可选,指定哪些响应头可以暴露给浏览器。allowCredentials
:是否允许凭证(如Cookies)。如果设置为true
,则不能使用通配符*
作为源。
完整注解参数
@CrossOrigin(
origins = {"https://example.com"},
methods = {RequestMethod.GET, RequestMethod.POST},
allowedHeaders = {"Authorization", "Content-Type"},
exposedHeaders = {"X-Custom-Header"},
allowCredentials = "true",
maxAge = 3600
)
方法 2:全局配置 CORS(WebMvcConfigurer)
如果你想要为所有端点配置CORS,或者定义多个CORS配置,可以通过实现 WebMvcConfigurer
接口并重写 addCorsMappings
方法来进行全局配置。
全局配置示例
// src/main/java/com/example/demo/config/WebConfig.java
package com.example.demo.config;
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 WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 匹配所有路径
.allowedOrigins("https://example.com") // 允许的源
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的HTTP方法
.allowedHeaders("*") // 允许的HTTP头
.allowCredentials(true) // 是否允许凭证
.maxAge(3600); // 预检请求结果缓存时间(秒)
}
}
注意事项
allowedOrigins
:指定允许的源,可以是一个具体的URL,也可以是通配符*
表示允许所有源。但是,如果你启用了凭证共享 (allowCredentials=true
),则不能使用通配符*
。allowedMethods
:指定允许的HTTP方法。allowedHeaders
:指定允许的HTTP头。allowCredentials
:如果设置为true
,则意味着响应将包含Access-Control-Allow-Credentials
头,这会告诉浏览器是否允许发送凭证信息(例如cookies)。如果启用了凭证,则不能将allowedOrigins
设置为*
。maxAge
:预检请求的结果可以被缓存的时间(以秒为单位)。
多路径配置示例
如果你需要为不同路径设置不同的CORS规则,可以在 addCorsMappings
方法中注册多个映射:
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("https://example.com")
.allowedMethods("GET", "POST")
.allowedHeaders("Authorization", "Content-Type")
.allowCredentials(true)
.maxAge(3600);
registry.addMapping("/admin/**")
.allowedOrigins("https://admin.example.com")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.allowCredentials(false)
.maxAge(3600);
}
方法 3:通过 CorsFilter
配置
对于更复杂的场景,比如你需要对不同的路径应用不同的CORS规则,或者你希望在应用程序启动时就注册CORS过滤器,你可以创建一个 CorsConfigurationSource
并注册一个 CorsFilter
。
自定义 CorsFilter
示例
// src/main/java/com/example/demo/config/CorsConfig.java
package com.example.demo.config;
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;
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// Path 1: /api/*
CorsConfiguration apiConfig = new CorsConfiguration();
apiConfig.setAllowCredentials(true);
apiConfig.addAllowedOrigin("https://example.com");
apiConfig.addAllowedHeader("Authorization");
apiConfig.addAllowedHeader("Content-Type");
apiConfig.addAllowedMethod("GET");
apiConfig.addAllowedMethod("POST");
source.registerCorsConfiguration("/api/**", apiConfig);
// Path 2: /admin/*
CorsConfiguration adminConfig = new CorsConfiguration();
adminConfig.setAllowCredentials(false);
adminConfig.addAllowedOrigin("https://admin.example.com");
adminConfig.addAllowedHeader("*");
adminConfig.addAllowedMethod("*");
source.registerCorsConfiguration("/admin/**", adminConfig);
return new CorsFilter(source);
}
}
多路径配置示例
如果你有多个路径需要不同的CORS规则,可以在 UrlBasedCorsConfigurationSource
中注册多个配置:
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// Path 1: /api/*
CorsConfiguration apiConfig = new CorsConfiguration();
apiConfig.setAllowCredentials(true);
apiConfig.addAllowedOrigin("https://example.com");
apiConfig.addAllowedHeader("Authorization");
apiConfig.addAllowedHeader("Content-Type");
apiConfig.addAllowedMethod("GET");
apiConfig.addAllowedMethod("POST");
source.registerCorsConfiguration("/api/**", apiConfig);
// Path 2: /admin/*
CorsConfiguration adminConfig = new CorsConfiguration();
adminConfig.setAllowCredentials(false);
adminConfig.addAllowedOrigin("https://admin.example.com");
adminConfig.addAllowedHeader("*");
adminConfig.addAllowedMethod("*");
source.registerCorsConfiguration("/admin/**", adminConfig);
return new CorsFilter(source);
}
高级配置选项
1. 处理凭证共享
当你需要处理凭证(如Cookies)时,确保正确设置了 allowCredentials
和 allowedOrigins
。记住,如果启用了凭证共享,你不能使用通配符 *
作为允许的源。
config.setAllowCredentials(true);
config.addAllowedOrigin("https://example.com"); // 必须明确指定源
2. 处理复杂头部
有时你需要处理特定的HTTP头部,而不是简单的通配符。你可以通过 setAllowedHeaders
方法来指定允许的头部。
config.addAllowedHeader("Authorization");
config.addAllowedHeader("Content-Type");
3. 处理多种来源
如果你有多个允许的来源,可以使用 setAllowedOrigins
方法来添加多个源。
config.addAllowedOrigin("https://example.com");
config.addAllowedOrigin("https://anotherdomain.com");
4. 处理预检请求
预检请求(Preflight Requests)是在某些跨域请求之前由浏览器自动发送的,用于检查服务器是否允许实际请求。你可以通过 setAllowCredentials
和 setMaxAge
来控制这些行为。
config.setAllowCredentials(true);
config.setMaxAge(3600L); // 缓存预检请求结果的时间(秒)
5. 暴露特定响应头
有时候你需要让客户端能够访问某些特定的响应头。你可以通过 setExposedHeaders
方法来指定这些响应头。
config.setExposedHeaders(Arrays.asList("X-Custom-Header"));
生产环境下的解决方案
1. 使用 Nginx 反向代理
Nginx 是一个高性能的HTTP和反向代理服务器,它可以帮助你将前端请求转发到后端API服务器,同时处理跨域问题。通过这种方式,你可以确保所有的请求都来自同一个域名,从而避免浏览器的同源策略限制。
Nginx 配置示例
假设你的前端应用部署在 http://example.com
,而后端API位于 http://backend.example.com
。你可以使用Nginx来设置反向代理:
# /etc/nginx/sites-available/example.com
server {
listen 80;
server_name example.com;
location / {
# 将所有前端静态资源请求指向Vue构建的静态文件目录
root /var/www/html/dist;
try_files $uri $uri/ /index.html;
}
location /api/ {
# 将/api/开头的请求转发给后端API服务器
proxy_pass http://backend.example.com/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
步骤:
-
安装 Nginx(如果尚未安装):
sudo apt update sudo apt install nginx
-
配置 Nginx:
- 创建或编辑
/etc/nginx/sites-available/example.com
文件。 - 使用上述配置示例进行修改,确保路径和域名正确。
- 创建或编辑
-
启用站点配置:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
-
测试配置并重启 Nginx:
sudo nginx -t sudo systemctl restart nginx
-
部署前端静态文件:
- 将Vue构建后的静态文件放置在
/var/www/html/dist
目录下。
- 将Vue构建后的静态文件放置在
-
确保后端API服务器正常运行:
- 确认
http://backend.example.com
可以访问,并且API服务正常工作。
- 确认
2. 前后端部署在同一域名下
如果可能的话,将前后端部署在同一域名下是解决跨域问题的最佳实践之一。这样做可以完全避免跨域问题,因为所有请求都来自同一源。
示例:
- 前端:部署在
https://example.com
- 后端API:部署在
https://api.example.com
如果你使用的是子域名(如 api.example.com
),你可以通过DNS配置和SSL证书来确保它们被视为同一源。另外,也可以考虑将API路由集成到主域名中(例如 https://example.com/api
)。