目錄導航
- 1.什麼是跨域?
- 2.同源政策
- 3.項目場景
- *4.解決方法(重點)
-
- (1)使用@CrossOrigin注解
- (2)使用corsfilter過濾器
- (3)全局跨域設定。(推薦)
-
-
- 繼承WebMvcConfigurer,通過addCorsMappings方法實作跨域通路。
-
- **(4)nginx反向代理(代理轉發)重要
1.什麼是跨域?
(1)簡單的來說,跨域就是浏覽器核心同源政策對JavaScript代碼的一種限制。例如在目前伺服器的網站下不可執行另外網站的js代碼。
(2)常見的例如:dom和js對象無法擷取,ajax請求伺服器資料顯示:No ‘Access-Control-Allow-Origin’ header is present on the requested resource.錯誤。
2.同源政策
(1)同源政策是浏覽器的行為,是為了保護本地資料不被JavaScript代碼擷取回來的資料污染,是以攔截的是用戶端發出的請求回來的資料接收,即請求發送了,伺服器響應了,但是無法被浏覽器接收。
(2)浏覽器判斷同源的标準:
首先分析一下一個url的組成:http://localhost:8080/xxx.html
協定:http https 都是常見的協定
ip:一般本機的ip都是127.0.0.1或localhost來代替。
端口:比如常見的網站端口預設是80,等等。
http://localhost/bbb.html 與 http://localhost/aaa.html 同源 協定 ip 端口都一緻
http://localhost/bbb.html 與 https://localhost/aaa.html 跨域 協定不一緻
http://localhost/bbb.html 與 http://127.0.0.1/aaa.html 跨域 ip 不一緻(浏覽器認為localhost和127.0.0.1是屬于跨域,很多人會混淆)
http://localhost/xxx.html 與 http://localhost:8080/xxx.html 端口不一緻 屬于跨域
3.項目場景
(1)前端項目釋出服務端口為80,後端服務端口為8081的情況下。這時候前端ajax請求後端服務就屬于跨域通路,傳回的資料将會被浏覽器攔截,進而報錯。(Allow-Origin’ header is present on the requested resource)
*4.解決方法(重點)
(1)使用@CrossOrigin注解
(2)使用corsfilter過濾器
整理好的代碼片段如下:
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.ArrayList;
import java.util.List;
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
final CorsConfiguration corsConfiguration = new CorsConfiguration();
//是否允許請求帶有驗證資訊
corsConfiguration.setAllowCredentials(true);
corsConfiguration.addAllowedOriginPattern("http://localhost:8081"); //單個域名設定
/*允許服務端通路的用戶端請求頭*/
corsConfiguration.addAllowedHeader("*");
/*允許通路的方法名,GET POST等*/
corsConfiguration.addAllowedMethod("*");
//注冊url路徑,/**為全部路徑比對
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
}
(3)全局跨域設定。(推薦)
繼承WebMvcConfigurer,通過addCorsMappings方法實作跨域通路。
代碼如下:
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("/**").allowedOriginPatterns("*")
//注冊可以請求的方法
.allowedMethods("GET", "HEAD", "POST","PUT", "DELETE", "OPTIONS")
.allowCredentials(true).maxAge(3600);
}
}
**(4)nginx反向代理(代理轉發)重要
先上配置,如下:配置檔案在安裝好的nginx路徑下的conf檔案夾中的nginx.conf檔案
events {
worker_connections 1024;
}
http{
server {
listen 8081;
server_name 192.168.1.100;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://192.168.1.100:8082;
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods $http_access_control_request_method;
add_header Access-Control-Allow-Headers $http_access_control_request_headers;
add_header Access-Control-Max-Age 1728000;
add_header Content-Length 300;
return 204;
}
}
}
}
- 首先,配置檔案一定要有events{}和http{server{}}。
- 其次,server{}中的listen則是代表我們監聽的服務端口。(這裡是監聽192.168.1.100:8081的服務,然後轉發到8082端口)。
- server_name則是伺服器的ip或域名。
- 最最最重要的就是location的配置,’/'代表比對所有192.168.1.100:8081發出的請求。例如:http:192.168.1.100:8081/xx/xxx.js就會被/比對。
- proxy_set_header:設定轉發後的請求頭的相關資訊
- X-Real-IP :設定真實請求的ip
- REMOTE-HOST:設定真實的請求的真實主機位址
- X-Forwarded-For:第一個ip為用戶端請求的ip,第二個則是代理ip(用戶端:http://localhost:8081,代理:http://localhost:8082)
- proxy_pass:代理轉發url。就是由nginx發送http://localhost:8082,這樣nginx和背景就處于同源下,這樣就實作跨域通路了。
-
注意: 當proxy_pass的url後面跟上/斜杆時,轉發的url有以下情況
假設現在用http://localhost:8081/aaa/xxx.html去通路。
① 當location /aaa/ {
proxy_pass http://localhost:8082
} 代理url:http://localhost:8082/aaa/xxx.html
② 當location /aaa/ {
proxy_pass http://localhost:8082/
} 代理url:http://localhost:8082/xxx.html
由①、②對比,可以知道,當轉發的url後面有斜杆時,就會将比對http://localhost:8081/aaa/變成http://localhost:8082/,如果沒有,則隻替換前面的協定+ip+端口。
③ 當location /aaa/ {
proxy_pass http://localhost:8082/bbb/
} 代理url:http://localhost:8082/bbb/xxx.html
④ 當location /aaa/ {
proxy_pass http://localhost:8082/bbb
} 代理url:http://localhost:8082/bbbxxx.html
由③、④對比,相同的是,都改變了url,不同的是,有斜杆的③分多了一級,而④是直接拼接。
- add_header:添加響應頭資訊。(跨域通路,并不是請求不到資料,而是接收不到資料)。是以,我們可以在響應頭中添加對應origin值,add_header Access-Control-Allow-Origin $http_origin; 這樣浏覽器就不會攔截。其他資料類似corsfilter配置的資訊,允許cookies、請求方法類型之類的,可自行上網查找。
-
$request_method = ‘OPTIONS’:浏覽器将cors請求(跨域請求)分為兩種。一是簡單請求。二是非簡單請求。隻要同時滿足以下兩大條件,就屬于簡單請求。
(1) 請求方法是以下三種方法之一:HEAD、GET、POST
(2)HTTP的頭資訊不超出以下幾種字段:Accept、Accept-Language、ContentLanguage、Last-Event-ID
(3)Content-Type:隻限于三個值application/x-www-form-urlencoded、multipart/form-data、text/plain
凡是不同時滿足上面兩個條件,就屬于非簡單請求。
簡單請求浏覽器會自動添加一些附加的頭資訊,而非簡單請求浏覽器會多出一次附加的請求(options)。options請求會在正式請求前發送,該請求測試接口是否通過,通過才會發送正式請求。你需要确認背景不會攔截該請求,否則你的正式請求将無法被發送。
跨域通路記錄。