這是一個或許對你有用的社群
《專案實戰(影片)》:從書中學,往事上“練” 《網際網路高頻面試題》:面朝簡歷學習,春暖花開 《架構 x 系統設計》:摧枯拉朽,掌控面試高頻場景題 《精進 Java 學習指南》:系統學習,網際網路主流技術棧 《必讀 Java 原始碼專欄》:知其然,知其所以然
這是一個或許對你有用的開源專案
國產 Star 破 10w+ 的開源專案,前端包括管理後臺 + 微信小程式,後端支援單體和微服務架構。功能涵蓋 RBAC 許可權、SaaS 多租戶、資料許可權、商城、支付、工作流、大屏報表、微信公眾號、ERP、CRM、AI 大模型等等功能:
Boot 多模組架構:https://gitee.com/zhijiantianya/ruoyi-vue-pro Cloud 微服務架構:https://gitee.com/zhijiantianya/yudao-cloud 影片教程:https://doc.iocoder.cn 【國內首批】支援 JDK 17/21 + SpringBoot 3.3、JDK 8/11 + Spring Boot 2.7 雙版本
-
跨域請求的背景和重要性 -
什麼是跨域 -
如何證明上述情況就是跨域? -
為什麼是這樣,而不是那樣 -
預檢請求 -
預檢請求關伺服器什麼事情 -
伺服器如何處理跨域呢,允許還是不允許? -
知識點回顧 -
SpringBoot允許跨域的後端程式碼 -
模擬跨域的JS程式碼
跨域請求的背景和重要性
背景
跨域請求的重要性
-
安全性: 瀏覽器的同源政策旨在保護使用者,防止惡意網站竊取資訊。跨域請求需要經過嚴格的檢查和配置,以確保資料傳輸的安全性。 -
使用者體驗: 跨域請求的限制可能會導致使用者在操作過程中遇到障礙,影響應用的流暢性和可用性。在我們的專案中,如果不及時解決跨域問題,將會直接影響客戶體驗和業務進展。 -
業務需求: 在某些情況下,業務需求可能需要不同來源的資源互動。例如,在我們開發的微信公眾號中,需要與後端服務進行資料互動,以完成使用者的選擇和定金繳納等操作。 -
快速迭代: 隨著專案的推進,及時處理跨域問題是確保專案快速上線的重要環節。在短時間內解決跨域配置,能夠為後續的功能擴充套件和業務發展打下良好的基礎。
基於 Spring Boot + MyBatis Plus + Vue & Element 實現的後臺管理系統 + 使用者小程式,支援 RBAC 動態許可權、多租戶、資料許可權、工作流、三方登入、支付、簡訊、商城等功能
專案地址:https://github.com/YunaiV/ruoyi-vue-pro 影片教程:https://doc.iocoder.cn/video/
什麼是跨域
為什麼有同源政策?
跨域的情形
http://www.bilibili.com
(假設存在)https://www.bilibili.com:8086
(假設存在)http://admin.www.bilibili.com
(假設存在)跨域原因解釋
admin.www.bilibili.com
是域名)變了
基於 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現的後臺管理系統 + 使用者小程式,支援 RBAC 動態許可權、多租戶、資料許可權、工作流、三方登入、支付、簡訊、商城等功能
專案地址:https://github.com/YunaiV/yudao-cloud 影片教程:https://doc.iocoder.cn/video/
如何證明上述情況就是跨域?

package
org.springframework.web.cors;
publicabstractclassCorsUtils
{
publicCorsUtils()
{
}
//方法名就直接體現了方法的作用,判斷是否是跨域請求
publicstaticbooleanisCorsRequest(HttpServletRequest request)
{
String origin = request.getHeader(
"Origin"
);
if
(origin ==
null
) {
returnfalse
;
}
else
{
UriComponents originUrl = UriComponentsBuilder.fromOriginHeader(origin).build();
String scheme = request.getScheme();
String host = request.getServerName();
int
port = request.getServerPort();
//上面的程式碼是從請求體中獲取協議,域名,埠的value值,拿到這些值就是為了和Origin作比較
//透過截圖也能看到Origin包含了scheme,host,port,他們分別是https,www.bilibili.com,443
return
!ObjectUtils.nullSafeEquals(scheme, originUrl.getScheme())
|| !ObjectUtils.nullSafeEquals(host, originUrl.getHost())
|| getPort(scheme, port) != getPort(originUrl.getScheme(), originUrl.getPort());
}
}
}
為什麼是這樣,而不是那樣


預檢請求
何時觸發預檢請求
複雜請求:
-
當使用的 HTTP 方法不是簡單請求中的 GET
或POST
(如PUT
、DELETE
)。 -
當請求中包含自定義頭部(例如, X-Custom-Header
)。 -
當 Content-Type 的值不是簡單請求允許的型別(如 application/x-www-form-urlencoded
、multipart/form-data
或text/plain
)。
伺服器端的 CORS 配置:
-
只有在伺服器配置了 CORS,並明確允許來自特定源的請求時,預檢請求才會返回成功。
預檢請求關伺服器什麼事情





publicstaticbooleanisPreFlightRequest(HttpServletRequest request)
{
//先判斷是不是OPTIONS請求,若是,則表示是預檢請求
return
HttpMethod.OPTIONS.matches(request.getMethod())
//預檢請求時,http請求頭一定要給Origin
&& request.getHeader(
"Origin"
) !=
null
//預檢請求時,會給定名為Access-Control-Request-Method的請求頭
&& request.getHeader(
"Access-Control-Request-Method"
) !=
null
;
}
伺服器如何處理跨域呢,允許還是不允許?



知識點回顧
ObjectUtils.isEmpty(this.allowedOrigins)
或者this.allowedOrigins.contains("*")
,if語句的條件不成立了,因為this.allowedOrigins
並不包含客戶端的域名,也就是例子中的https://www.bilbili.com
或者https://www.zhihu.com
,我們要處理的正是allowedOrigins
,private
List<String> allowedOrigins;
SpringBoot允許跨域的後端程式碼
@Configuration
publicclassCorsConfig
{
@Bean
public CorsFilter corsFilter()
{
UrlBasedCorsConfigurationSource source =
new
UrlBasedCorsConfigurationSource();
CorsConfiguration config =
new
CorsConfiguration();
//config.setAllowCredentials(true); // 允許傳送憑據,雷區
config.addAllowedOrigin(
"*"
);
//允許任意域名跨域訪問介面
config.addAllowedHeader(
"*"
);
// 允許所有頭部資訊
config.addAllowedMethod(
"*"
);
// 允許所有請求方法
source.registerCorsConfiguration(
"/**"
, config);
// 應用於所有路徑
returnnew
CorsFilter(source);
}
}
config.addAllowedOrigin("*");
不可以一起使用,否則會報錯。到這裡,一切OK,前端跨域的問題已經解決~模擬跨域的JS程式碼
var
xhr =
new
XMLHttpRequest();
xhr.open(
'post'
,
'http://localhost:8081/admin/captcha/v1/generateCaptcha'
);
xhr.setRequestHeader(
'Content-Type'
,
'application/json'
);
// 設定請求頭
xhr.setRequestHeader(
'authracation'
,
'abcdefghijklmnopqrstuvwxyz'
);
// 設定請求頭
xhr.onload = function(e) {
var
xhr = e.target;
console.log(xhr.responseText);
};
xhr.send(
'{}'
);





