在Spring Boot中,跨域是指當瀏覽器中的前端應用(如運行在某個域名和端口下的前端頁面)請求后端接口時,如果后端接口所在的域名、端口或協議與前端應用不一致,瀏覽器會阻止這種跨域請求。這是由于瀏覽器的同源策略(Same-Origin Policy)所導致的。
跨域產生的原因
瀏覽器出于安全性考慮,會阻止不同來源(域名、端口或協議不同)之間的請求
-
同源策略限制:瀏覽器出于安全考慮,實施了同源策略,即只允許頁面請求同源(相同協議、域名和端口)的資源。當JavaScript發起的請求跨越了同源策略,即請求的目標與當前頁面的域名、端口、協議不一致時,瀏覽器會阻止請求的發送或接收。
-
前后端分離架構:在現代的前后端分離開發模式下,前端和后端通常部署在不同的服務器上,具有不同的域名或端口,這很容易導致跨域問題。
例如:
- 前端運行在
http://localhost:3000
- 后端 API 在
http://localhost:8080
當前端向 http://localhost:8080/api/data
發送請求時,瀏覽器會攔截并報 CORS policy
錯誤。
解決跨域問題的常見方式
方式 1:使用 @CrossOrigin
注解(推薦小型項目或單個接口)
在 Spring Boot 控制器(@RestController
)上使用 @CrossOrigin
注解,允許跨域訪問:
1) 允許所有來源訪問整個控制器
@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "*") // 允許所有來源
public class MyController {@GetMapping("/data")public String getData() {return "Hello, CORS!";}
}
2) 只允許特定的來源
@CrossOrigin(origins = "http://localhost:3000") // 只允許從 http://localhost:3000 訪問
@GetMapping("/data")
public String getData() {return "Hello, CORS!";
}
3) 細粒度控制(支持多個來源、方法、請求頭)
@CrossOrigin(origins = {"http://localhost:3000", "http://example.com"},methods = {RequestMethod.GET, RequestMethod.POST},allowedHeaders = {"Content-Type", "Authorization"})
@GetMapping("/data")
public String getData() {return "CORS Configured!";
}
方式 2:全局配置(推薦大型項目或所有接口都需要跨域)
如果所有 API 都需要支持跨域,使用 CorsFilter
或 WebMvcConfigurer
進行全局配置。
2.1) 使用 WebMvcConfigurer
配置全局 CORS,在 @Configuration
類中注冊 CORS 規則:
-
在Spring Boot應用中,可以通過創建一個配置類,實現
WebMvcConfigurer
接口,并重寫addCorsMappings
方法來全局配置跨域訪問。這種方式適用于所有接口都需要跨域訪問的場景。
import org.springframework.context.annotation.Bean;
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 CorsConfig {@Beanpublic WebMvcConfigurer corsConfigurer() {return new WebMvcConfigurer() {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**") // 允許所有路徑.allowedOrigins("http://localhost:3000") // 允許特定域訪問.allowedMethods("GET", "POST", "PUT", "DELETE") // 允許的請求方法.allowedHeaders("*") // 允許所有請求頭.allowCredentials(true); // 允許攜帶 Cookie}};}
}
addMapping("/**")
:允許所有接口跨域allowedOrigins("http://localhost:3000")
:只允許http://localhost:3000
訪問allowedMethods("GET", "POST", "PUT", "DELETE")
:允許這些 HTTP 方法allowedHeaders("*")
:允許所有請求頭allowCredentials(true)
:允許攜帶cookies
或Authorization
頭
2.2) 使用 CorsFilter
配置 CORS
另一種方式是使用 CorsFilter,這種方式也是通過Java配置的方式配置跨域訪問,與全局配置CORS類似,但實現方式略有不同。
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 java.util.Arrays;@Configuration
public class MyCorsFilter {@Beanpublic CorsFilter corsFilter() {UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();CorsConfiguration config = new CorsConfiguration();config.setAllowedOrigins(Arrays.asList("http://localhost:3000")); // 允許的前端地址config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));config.setAllowedHeaders(Arrays.asList("*"));config.setAllowCredentials(true); // 允許 Cookiesource.registerCorsConfiguration("/**", config);return new CorsFilter(source);}
}
setAllowedOrigins(Arrays.asList("http://localhost:3000"))
:指定允許的域setAllowCredentials(true)
:允許帶 Cookies(必須與allowedOrigins
不能設置為"*"
)
方式3. 允許攜帶 Cookie
如果前端需要攜帶 cookie
或 Authorization
頭,例如 fetch
或 Axios
發送請求時 credentials: 'include'
,你需要:
- 在后端
allowCredentials(true)
- 在前端請求時
credentials: 'include'
后端
registry.addMapping("/**").allowedOrigins("http://localhost:3000").allowedMethods("GET", "POST").allowCredentials(true); // 允許攜帶 Cookie
前端(使用 Fetch)
fetch('http://localhost:8080/api/data', {method: 'GET',credentials: 'include' // 允許攜帶 Cookie
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
前端(使用 Axios)
axios.get('http://localhost:8080/api/data', { withCredentials: true }).then(response => console.log(response.data)).catch(error => console.error(error));
方式4. 通過Nginx配置CORS
如果項目中使用了Nginx作為反向代理服務器,也可以在Nginx中配置CORS來解決跨域問題。
server {...location / {add_header 'Access-Control-Allow-Origin' '*';add_header 'Access-Control-Allow-Headers' '*';add_header 'Access-Control-Allow-Methods' '*';if ($request_method = 'OPTIONS') {return 204;}}...
}
通過以上方法,可以在Spring Boot應用中有效地解決跨域問題,確保前后端之間的正常通信。
常見 CORS 錯誤及解決方法
錯誤信息 | 可能原因 | 解決方案 |
---|---|---|
Access to fetch at 'http://localhost:8080' from origin 'http://localhost:3000' has been blocked by CORS policy | 后端未配置 CORS | 配置 @CrossOrigin 或 WebMvcConfigurer |
Response to preflight request doesn’t pass access control check | OPTIONS 請求被攔截 | 在后端允許 OPTIONS 方法 |
Missing Allow-Control-Allow-Origin header | CORS 頭未返回 | 確保后端 allowedOrigins 設置正確 |
credentials mode is 'include' but Access-Control-Allow-Credentials is missing | 需要攜帶 Cookie 但未允許 | 在后端 allowCredentials(true) |
總結
方法 | 適用場景 | 配置方式 |
---|---|---|
@CrossOrigin | 適用于單個接口 | 在 @RestController 或方法級別使用 |
WebMvcConfigurer | 適用于整個項目 | CorsRegistry 配置 |
CorsFilter | 高級定制 | 使用 CorsConfiguration |
在 Spring Boot 項目中,推薦使用 WebMvcConfigurer
進行全局跨域配置,@CrossOrigin
適用于局部控制。