掃二維碼與項目經(jīng)理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術咨詢/運營咨詢/技術建議/互聯(lián)網(wǎng)交流
跨域問題指的是不同站點之間,使用 ajax 無法相互調(diào)用的問題??缬騿栴}本質(zhì)是瀏覽器的一種保護機制,它的初衷是為了保證用戶的安全,防止惡意網(wǎng)站竊取數(shù)據(jù)。但這個保護機制也帶來了新的問題,它的問題是給不同站點之間的正常調(diào)用,也帶來的阻礙,那怎么解決這個問題呢?接下來我們一起來看。

創(chuàng)新互聯(lián)建站是一家集網(wǎng)站建設,東烏珠穆沁企業(yè)網(wǎng)站建設,東烏珠穆沁品牌網(wǎng)站建設,網(wǎng)站定制,東烏珠穆沁網(wǎng)站建設報價,網(wǎng)絡營銷,網(wǎng)絡優(yōu)化,東烏珠穆沁網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強企業(yè)競爭力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時我們時刻保持專業(yè)、時尚、前沿,時刻以成就客戶成長自我,堅持不斷學習、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實用型網(wǎng)站。
在請求時,如果出現(xiàn)了以下情況中的任意一種,那么它就是跨域請求:
也就是說,即使域名相同,如果一個使用的是 http,另一個使用的是 https,那么它們也屬于跨域訪問。常見的跨域問題如下圖所示:
接下來,我們使用兩個 Spring Boot 項目來演示跨域的問題,其中一個是端口號為 8080 的前端項目,另一個端口號為 9090 的后端接口項目。
前端項目只需要在 resources 下放兩個文件,一個用于發(fā)送 ajax 請求的 jquery.js,另一個是 html 前端頁面,工程目錄如下圖所示:
其中前端頁面 index.html 的代碼如下:
跨域測試頁面
跨域測試
后端接口項目首先先在 application.properties 配置文件中,設置項目的端口號為 9090,如下所示:
server.port=9090
然后創(chuàng)建一個后端控制器,返回一個 JSON 格式的數(shù)據(jù),實現(xiàn)代碼如下:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
@RestController
public class TestController {
@RequestMapping("/test")
public HashMaptest() {
return new HashMap() {{
put("state", 200);
put("data", "success");
put("msg", "");
}};
}
}
以上兩個項目創(chuàng)建并啟動成功之后,使用前端項目訪問后端接口,因為端口不一樣,所以也屬于跨域訪問,運行結(jié)果如下圖所示:
在 Spring Boot 中跨域問題有很多種解決方案,比如以下 5 個:
當然如果你愿意的話,還可以使用過濾器來實現(xiàn)跨域,但它的實現(xiàn)和第 5 種實現(xiàn)類似,所以本文就不贅述了。
使用 @CrossOrigin 注解可以輕松的實現(xiàn)跨域,此注解既可以修飾類,也可以修飾方法。當修飾類時,表示此類中的所有接口都可以跨域;當修飾方法時,表示此方法可以跨域,它的實現(xiàn)如下:
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
@RestController
@CrossOrigin(origins = "*")
public class TestController {
@RequestMapping("/test")
public HashMaptest() {
return new HashMap() {{
put("state", 200);
put("data", "success");
put("msg", "");
}};
}
}
以上代碼的執(zhí)行結(jié)果如下圖所示:
從上圖中可以看出,前端項目訪問另一個后端項目成功了,也就說明它解決了跨域問題。優(yōu)缺點分析此方式雖然雖然實現(xiàn)(跨域)比較簡單,但細心的朋友也能發(fā)現(xiàn),使用此方式只能實現(xiàn)局部跨域,當一個項目中存在多個類的話,使用此方式就會比較麻煩(需要給所有類上都添加此注解)。
接下來我們通過設置配置文件的方式就可以實現(xiàn)全局跨域了,它的實現(xiàn)步驟如下:
具體實現(xià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 CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 所有接口
.allowCredentials(true) // 是否發(fā)送 Cookie
.allowedOriginPatterns("*") // 支持域
.allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"}) // 支持方法
.allowedHeaders("*")
.exposedHeaders("*");
}
}
此實現(xiàn)方式和上一種實現(xiàn)方式類似,它也可以實現(xiàn)全局跨域,它的具體實現(xià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;
@Configuration // 一定不能忽略此注解
public class MyCorsFilter {
@Bean
public CorsFilter corsFilter() {
// 1.創(chuàng)建 CORS 配置對象
CorsConfiguration config = new CorsConfiguration();
// 支持域
config.addAllowedOriginPattern("*");
// 是否發(fā)送 Cookie
config.setAllowCredentials(true);
// 支持請求方式
config.addAllowedMethod("*");
// 允許的原始請求頭部信息
config.addAllowedHeader("*");
// 暴露的頭部信息
config.addExposedHeader("*");
// 2.添加地址映射
UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
corsConfigurationSource.registerCorsConfiguration("/**", config);
// 3.返回 CorsFilter 對象
return new CorsFilter(corsConfigurationSource);
}
}
此方式是解決跨域問題最原始的方式,但它可以支持任意的 Spring Boot 版本(早期的 Spring Boot 版本也是支持的)。但此方式也是局部跨域,它應用的范圍最小,設置的是方法級別的跨域,它的具體實現(xiàn)代碼如下:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
@RestController
public class TestController {
@RequestMapping("/test")
public HashMaptest(HttpServletResponse response) {
// 設置跨域
response.setHeader("Access-Control-Allow-Origin", "*");
return new HashMap() {{
put("state", 200);
put("data", "success");
put("msg", "");
}};
}
}
通過重寫 ResponseBodyAdvice 接口中的 beforeBodyWrite(返回之前重寫)方法,我們可以對所有的接口進行跨域設置,它的具體實現(xiàn)代碼如下:
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
/**
* 內(nèi)容是否需要重寫(通過此方法可以選擇性部分控制器和方法進行重寫)
* 返回 true 表示重寫
*/
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
/**
* 方法返回之前調(diào)用此方法
*/
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {
// 設置跨域
response.getHeaders().set("Access-Control-Allow-Origin", "*");
return body;
}
}
此實現(xiàn)方式也是全局跨域,它對整個項目中的所有接口有效。
為什么通過以上方法設置之后,就可以實現(xiàn)不同項目之間的正常交互呢?這個問題的答案也很簡單,我們之前在說跨域時講到:“跨域問題本質(zhì)是瀏覽器的行為,它的初衷是為了保證用戶的訪問安全,防止惡意網(wǎng)站竊取數(shù)據(jù)”,那想要解決跨域問題就變得很簡單了,只需要告訴瀏覽器這是一個安全的請求,“我是自己人”就行了,那怎么告訴瀏覽器這是一個正常的請求呢?只需要在返回頭中設置“Access-Control-Allow-Origin”參數(shù)即可解決跨域問題,此參數(shù)就是用來表示允許跨域訪問的原始域名的,當設置為“*”時,表示允許所有站點跨域訪問,如下圖所示:
所以以上 5 種解決跨域問題的本質(zhì)都是給響應頭中加了一個 Access-Control-Allow-Origin 的響應頭而已。
https://gitee.com/mydb/springboot-examples/tree/master/spring-boot-cross
跨域問題的本質(zhì)是瀏覽器為了保證用戶的一種安全攔截機制,想要解決跨域問題,只需要告訴瀏覽器“我是自己人,不要攔我”就行。它的常見實現(xiàn)方式有 5 種:通過注解實現(xiàn)局部跨域、通過配置文件實現(xiàn)全局跨域、通過 CorsFilter 對象實現(xiàn)全局跨域、通過 Response 對象實現(xiàn)局部跨域,通過 ResponseBodyAdvice 實現(xiàn)全局跨域。
blog.csdn.net/pjmike233/article/details/82461911

我們在微信上24小時期待你的聲音
解答本文疑問/技術咨詢/運營咨詢/技術建議/互聯(lián)網(wǎng)交流