SpringBoot學會自己寫配置類及跨域解析


前言

相信剛開始接觸從xml配置文件轉到java類實現配置功能的過程中,些許都會有些疑惑,配置文件到底該怎么寫,我要實現多少接口,new多少對象,完全不知道怎么入手。

今天,在學習了跨域的相關配置后,學到了一點點自定義配置的思路。在此做下記錄,也為學習討論。本文主體分為兩部分,第一部分介紹跨域問題,第二部分介紹如何編寫配置類


聊聊跨域

跨域的本質是瀏覽器針對ajax請求,規定當前頁面下發送的ajax請求的域名應該和當前頁面的域名一致,達到阻止跨站攻擊的目的。通常該跨域問題只針對ajax,而不會針對靜態文件(圖片等)

而以下四種情況會導致跨域問題:

條件 示例
域名不同 www.a.com與www.b.com
域名相同端口不同 www.a.com:80與www.a.com:81
二級域名不同 x.a.com與y.a.com
協議不同 http與https

解決跨域的方法

解決跨域的方法有以下三種

  • Jsonp

    • 實現方法:通過<script>標簽的src發送請求路徑獲取偽裝成js腳本的json數據

    • 缺點:只能發送GET請求,添加額外標簽繁瑣

  • nginx反向代理

    • 實現方法:修改nginx配置,添加二級域名到server的location路徑下
    • 缺點:沒解決本質問題,只是將跨域改為不跨越
  • CORS(推薦)

    • 實現方法:服務器端通知瀏覽器哪些域名可以跨域
    • 缺點:產生額外請求(預檢請求)

什么是CORS?

CORS全稱Cross-origin resource sharing(跨域資源共享)為W3C的一個標准,它允許瀏覽器向跨源服務器,發出XMLHttpRequest(ajax底層對象)請求,從而克服了AJAX只能同源使用的限制。

瀏覽器處理Ajax請求

瀏覽器處理ajax請求分為簡單請求和特殊請求

簡單請求

只要同時滿足以下兩大條件,就屬於簡單請求。:

(1) 請求方法是以下三種方法之一:

  • HEAD
  • GET
  • POST

(2)HTTP的頭信息不超出以下幾種字段:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type:只限於三個值application/x-www-form-urlencodedmultipart/form-datatext/plain

簡單請求重點:

當瀏覽器發現發起的ajax請求是簡單請求時,會在請求頭中攜帶一個字段:Origin

簡單請求過程解析:

瀏覽器會在請求頭信息攜帶Origin字段(例:Origin:http://a.baidu.com{協議+域名+端口}),服務器根據該Origin值決定是否允許跨域

響應信息:

Access-Control-Allow-Origin: http://a.baidu.com 
Access-Control-Allow-Credentials: true
Content-Type: text/html; charset=utf-8
  • Access-Control-Allow-Origin:可接受的域,是一個具體域名或者*(代表任意域名)
  • Access-Control-Allow-Credentials:是否允許攜帶cookie,默認情況下,cors不會攜帶cookie,除非這個值是true

注意事項:

如果要使用cookie除了設置Access-Control-Allow-Credentials: true外,Access-Control-Allow-Origin: http://a.baidu.com 必須為具體的域名!!!

特殊請求

除了簡單請求之外,都為特殊請求

特殊請求重點:

特殊請求會在正式通信之前,增加一次HTTP查詢請求,稱為"預檢"請求(preflight)。該預檢請求會在請求頭攜帶一個OPTIONS字段

特殊請求過程解析(有關判斷使用三元運算符?:)

發送預檢請求==》服務器檢查該域名是否在許可名單中?答復瀏覽,瀏覽器發送正式XMLHttpRequest請求:報錯

預檢請求模板:

OPTIONS /cors HTTP/1.1
Origin: http://a.baidu.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.leyou.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

與簡單請求相比,除了Origin以外,多了兩個頭:

  • Access-Control-Request-Method:接下來會用到的請求方式,比如PUT
  • Access-Control-Request-Headers:會額外用到的頭信息

答復瀏覽器模板:

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://a.baidu.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Max-Age: 1728000
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

除了Access-Control-Allow-OriginAccess-Control-Allow-Credentials以外,這里又額外多出3個頭:

  • Access-Control-Allow-Methods:允許訪問的方式
  • Access-Control-Allow-Headers:允許攜帶的頭
  • Access-Control-Max-Age:本次許可的有效時長,單位是秒,過期之前的ajax請求就無需再次進行預檢了

通過CorsFilter解決跨域

終於到了激動人心的擼碼環節了,以下開始介紹如何編寫配置類,以解決跨域問題

@Configuration注解

作用於類上,聲明當前類為配置類,相當於xml文件

@Bean

作用於方法上,將當前方法的返回值對象注入spring容器上下文(contex)中

1. 明確需要返回的對象

因為本次為了解決跨域問題,所以需要使用CorsFilter對象。因此直接return new CorsFilter();

2. 查看該對象需要哪些參數

點進CorsFilter發現該構造方法需要一個CorsConfigurationSource對象作為參數

public CorsFilter(CorsConfigurationSource configSource) {
		Assert.notNull(configSource, "CorsConfigurationSource must not be null");
		this.configSource = configSource;
	}

所以需要new出一個CorsConfigurationSource的對象,但是點進CorsConfigurationSource發現該類為一個接口,因此應該找一個實現類進行實例化

3. 尋找接口實現類

點擊該CorsConfigurationSource接口發現有一個實現類(UrlBasedCorsConfigurationSource)實現了該接口

public class UrlBasedCorsConfigurationSource implements CorsConfigurationSource

接着通過new該實現類(UrlBasedCorsConfigurationSource),通過閱讀源碼的注釋了解到,該類下的registerCorsConfiguration可以注冊CORS配置信息

     /**
	 * Register a {@link CorsConfiguration} for the specified path pattern.
	 */
	public void registerCorsConfiguration(String path, CorsConfiguration config) {
		this.corsConfigurations.put(path, config);
	}

根據該信息發現該方法需要兩個參數,一個是需要攔截的路徑,一個是配置類對象

4. 實例化配置類對象並注入相關信息

如法炮制,通過查看CorsConfiguration源碼,發現該類可以直接new,並且有無參構造方法,所以,直接new對象,並對該對象屬性賦初始值,完成該配置類的構造。

最后,將所有初始化后的對象賦值到方法的參數列表中


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM