Springboot解決跨域問題的實現(xiàn)方案
Springboot如何解決跨域問題?
在前后端分離架構(gòu)中,跨域問題是Java開發(fā)者繞不開的“基礎(chǔ)門檻”。本文從跨域的本質(zhì)(同源策略)出發(fā),系統(tǒng)講解SpringBoot中5種主流跨域方案,每個方案包含原理解析+可運行代碼+適用場景,幫你徹底解決跨域問題。
一、先搞懂:為什么會有跨域?
跨域的根源是瀏覽器的同源策略(Same-Origin Policy)——這是瀏覽器的安全機制,要求請求的“源”必須與當前頁面的“源”完全一致,才允許交互。也就是說在兩個后端之間互相調(diào)用接口是沒有跨域問題的。
1.1 同源的定義
“源”由三部分組成,三者完全相同才叫“同源”:
- 協(xié)議(如
http/https) - 域名(如
localhost/www.xxx.com) - 端口(如
8080/8090)
示例:當前頁面是http://localhost:8080,以下請求會被判定為跨域:
https://localhost:8080(協(xié)議不同)http://127.0.0.1:8080(域名不同)http://localhost:8090(端口不同)
1.2 跨域的表現(xiàn)
瀏覽器會攔截跨域請求,控制臺拋出類似錯誤:
Access to XMLHttpRequest at 'http://localhost:8081/api' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
二、方案1:JSONP(基本不用)
JSONP是早期跨域方案,前端后端需要同時更改,需要增加一個callback請求參數(shù),當然這個callback參數(shù)也可以自定義。
2.1 原理
- 前端通過
<script>標簽請求后端接口,傳遞回調(diào)函數(shù)名(如callback=handleData); - 后端將數(shù)據(jù)包裹在回調(diào)函數(shù)中返回(如
handleData({"msg":"success"})); - 前端提前定義回調(diào)函數(shù),接收并處理數(shù)據(jù)。
2.2 實戰(zhàn)代碼
后端接口
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class JsonpController {
/**
* JSONP接口:接收前端傳遞的callback參數(shù),返回包裹后的JSON
*/
@GetMapping("/info")
public String jsonpInfo(@RequestParam String callback) {
// 模擬返回的數(shù)據(jù)(比如根據(jù)id=16查詢到的信息)
String data = "{\"code\":200,\"msg\":\"success\",\"data\":{\"id\":16,\"name\":\"測試數(shù)據(jù)\",\"desc\":\"JSONP跨域示例\"}}";
// 拼接JSONP格式的響應(yīng)(回調(diào)函數(shù)名 + 數(shù)據(jù))
return callback + "(" + data + ")";
}
}
前端測試
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>jQuery Ajax JSONP跨域示例</title>
<!-- 引入jQuery -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
</head>
<body>
<button id="submitBtn">發(fā)起JSONP請求</button>
<script>
$("#submitBtn").click(function () {
$.ajax({
url: 'http://localhost:8080/info?id=16', // 后端接口地址(帶參數(shù)id=16)
type: 'GET', // JSONP僅支持GET請求
dataType: 'jsonp', // 關(guān)鍵:指定數(shù)據(jù)類型為jsonp
jsonp: 'callback', // 告訴后端:前端用callback參數(shù)傳遞回調(diào)函數(shù)名(默認就是callback,可省略)
success: function (response) {
// 成功接收后端返回的數(shù)據(jù)
console.log("JSONP請求成功,返回數(shù)據(jù):", response);
alert("請求成功!數(shù)據(jù)ID:" + response.data.id + ",名稱:" + response.data.name);
},
error: function (err) {
console.error("JSONP請求失?。?, err);
alert("請求失敗,請檢查控制臺");
}
});
});
</script>
</body>
</html>
2.3 適用場景
僅適用于簡單GET請求,或需要兼容老舊瀏覽器(如IE)的場景,不推薦現(xiàn)代項目使用。
三、方案2:全局配置(WebMvcConfigurer)
這是SpringBoot中最常用、最優(yōu)雅的跨域方案,通過配置全局CORS規(guī)則實現(xiàn)。
3.1 原理
基于W3C的CORS標準,服務(wù)端通過響應(yīng)頭告知瀏覽器“允許哪些源的請求”,核心響應(yīng)頭包括:
Access-Control-Allow-Origin:允許的跨域源;Access-Control-Allow-Methods:允許的請求方法;Access-Control-Allow-Credentials:是否允許攜帶Cookie。
3.2 實戰(zhàn)代碼
全局配置類
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 GlobalCorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 匹配所有接口
.allowedOriginPatterns("*") // 允許所有源(生產(chǎn)環(huán)境建議指定域名)
.allowedMethods("GET", "POST", "PUT", "DELETE") // 允許的請求方法
.allowedHeaders("*") // 允許所有請求頭
.allowCredentials(true) // 允許攜帶Cookie
.maxAge(3600); // 預(yù)檢請求緩存1小時
}
}
測試接口
@RestController
public class TestController {
@GetMapping("/api/test/get")
public String testGet() {
return "GET跨域成功";
}
@PostMapping("/api/test/post")
public String testPost(@RequestBody String data) {
return "POST跨域成功,接收:" + data;
}
}
前端測試(Axios)
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<button onclick="axios.get('http://localhost:8080/api/test/get').then(res=>alert(res.data))">測試GET</button>
<button onclick="axios.post('http://localhost:8080/api/test/post', {name:'張三'}).then(res=>alert(res.data))">測試POST</button>
3.3 適用場景
前后端分離的現(xiàn)代項目,推薦作為默認方案使用。
四、方案3:CorsFilter(官方Filter方案)
通過Spring官方的CorsFilter實現(xiàn)跨域,比手動寫Filter更規(guī)范、更靈活。
4.1 原理
CorsFilter是Spring封裝的CORS過濾器,通過CorsConfiguration配置規(guī)則,再綁定到指定路徑,自動攔截請求并添加跨域響應(yīng)頭。
4.2 實戰(zhàn)代碼
配置類
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.Collections;
@Configuration
public class CorsFilterConfig {
@Bean
public CorsFilter corsFilter() {
// 1. 配置跨域規(guī)則
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOriginPatterns(Collections.singletonList("*"));
config.addAllowedHeader(CorsConfiguration.ALL);
config.addAllowedMethod(CorsConfiguration.ALL);
config.setAllowCredentials(true);
config.setMaxAge(3600L);
// 2. 綁定路徑
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config); // 所有路徑應(yīng)用規(guī)則
// 3. 返回CorsFilter
return new CorsFilter(source);
}
}
4.3 適用場景
需要更靈活的跨域邏輯(如動態(tài)調(diào)整跨域規(guī)則),或項目中已使用Filter鏈的場景。
五、方案4:局部配置(@CrossOrigin注解)
僅為個別接口/Controller配置跨域,優(yōu)先級高于全局配置。
5.1 原理
@CrossOrigin是Spring提供的注解,底層基于CORS機制,為標注的接口自動添加跨域響應(yīng)頭。
5.2 實戰(zhàn)代碼
單個接口配置
@RestController
public class CrossOriginController {
@CrossOrigin(origins = "*", maxAge = 3600)
@GetMapping("/api/cross/test")
public String crossTest() {
return "單個接口跨域成功";
}
}
Controller級配置
@CrossOrigin(origins = "http://localhost:8080") // 僅允許8080源
@RestController
public class CrossOriginController2 {
@GetMapping("/api/cross/test2")
public String crossTest2() {
return "Controller級跨域成功";
}
}
5.3 適用場景
個別接口需要單獨配置跨域的場景,不推薦全局使用。
六、方案對比與選型建議
| 方案 | 適用場景 | 優(yōu)點 | 缺點 |
|---|---|---|---|
| JSONP | 簡單GET請求、兼容老舊瀏覽器 | 實現(xiàn)簡單 | 僅支持GET、有安全風險 |
| WebMvcConfigurer | 前后端分離全局跨域 | 優(yōu)雅簡潔、易維護 | 靈活性稍弱 |
| CorsFilter | 復雜跨域規(guī)則、Filter鏈場景 | 靈活可控、官方規(guī)范 | 代碼量略多 |
| @CrossOrigin | 個別接口/Controller跨域 | 局部配置、無需全局修改 | 不適合全局場景 |
到此這篇關(guān)于Springboot解決跨域問題的實現(xiàn)方案的文章就介紹到這了,更多相關(guān)Springboot跨域內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring?中?PageHelper?不生效問題及解決方法
這篇文章主要介紹了Spring?中?PageHelper?不生效問題,使用這個插件時要注意版本的問題,不同的版本可能 PageHelper 不會生效,本文結(jié)合示例代碼給大家介紹的非常詳細,需要的朋友可以參考下2022-12-12
mybatis實現(xiàn)獲取入?yún)⑹荓ist和Map的取值
這篇文章主要介紹了mybatis實現(xiàn)獲取入?yún)⑹荓ist和Map的取值問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06
Java中如何將json字符串轉(zhuǎn)換成map/list
這篇文章主要介紹了Java中如何將json字符串轉(zhuǎn)換成map/list,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07

