目錄
- 一,跨域產生的原因
- 二,什么情況下算跨域
- 三,實際演示
- 四,解決跨域的方法
-
- 1,@CrossOrigin注解
- 2,添加全局過濾器
- 3,實現WebMvcConfigurer
- 4,Nginx解決跨域
- 5,注意
開發項目的時候因為瀏覽器同源策略的限制,經常會遇到跨域問題,本篇文章對常見的跨域解決方案做一個記錄。
一,跨域產生的原因
之所以產生跨域主要是因為瀏覽器同源策略的限制。
同源策略,它是由NetSpace提出的一個著名的安全策略。
當一個瀏覽器的兩個tab頁中分別打開來自百度和谷歌的頁面,當瀏覽器的百度tab頁執行一個腳本的時候會檢查這個腳本是屬于哪個頁面的,即檢查是否同源,只有和百度同源的腳本才會被執行。如果非同源,那么在請求數據時,瀏覽器會在控制臺中報一個異常,提示拒絕訪問。
二,什么情況下算跨域
一個域名地址由以下幾個部分組成:
http://www.aaa.com:8080/sie=UTF-8&wd=SpringBoot
- 協議:http
- 域名:子域名www,主域名aaa.com
- 端口:8080
從一個域名的網頁去請求另一個域名的資源時,協議,域名,端口任意不同,都會出現跨域問題。
http://www.aaa.com:8080——>http://www.aaa.com:8080:同域訪問
http://www.aaa.com:8080——>http://www.bbb.com:8080:跨域訪問
尤其是在前后端分離的開發模式下,跨域請求是避免不了的。
三,實際演示
下面我們以一個實際功能為例:用戶輸入用戶名密碼,發往服務端驗證。
因為瀏覽器同源策略的限制,在瀏覽器控制臺提示我們:
Access to XMLHttpRequest at ‘http://192.168.1.10:7080/tick-tack/login’ from origin ‘http://192.168.1.10:7060’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
我們還可以在Network里看到,瀏覽器在發送我們輸入的用戶名,密碼等數據之前,還發送了一次OPTIONS的請求,這是瀏覽器自動發送的,為了驗證是否允許跨域訪問。
四,解決跨域的方法
我們已經知道,瀏覽器在發送請求之前會先發送一個OPTIONS請求,來校驗是否允許跨域訪問,校驗的結果存放在頭信息的Access-Control-Allow-Origin,因此解決跨域也就是設置頭部信息。有四種方法解決跨域。
1,@CrossOrigin注解
我們可以在特定的某些接口加上@CrossOrigin注解,表示該接口允許跨域訪問。注:未加該注解的接口仍不允許跨域訪問
@PostMapping("/login")
@CrossOrigin
public Result loginSystem(@RequestBody LoginUser user) {if (StringUtils.isBlank(user.getUserAccount()) || StringUtils.isBlank(user.getPassword())) {return Result.error(Constants.CODE_400, "參數錯誤");}TickToken tickToken = ILoginService.loginSystem(user);return Result.success(tickToken);
}
@CrossOrigin注解中的origins還可設置域名,表示只有該域名訪問時允許跨域,如:@CrossOrigin(origins =“http://localhost:7060”);
若origins未設置值,表示所有域名都可以跨域訪問該接口
2,添加全局過濾器
若項目中所有接口都允許跨域訪問,可增加全局過濾器允許跨域訪問。
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 CorsConfig {// 當前跨域請求最大有效時長。這里默認1天private static final long MAX_AGE = 24 * 60 * 60;@Beanpublic CorsFilter corsFilter() {UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();CorsConfiguration corsConfiguration = new CorsConfiguration();corsConfiguration.addAllowedOrigin("*"); // 1 設置訪問源地址,或者http://localhost:7060corsConfiguration.addAllowedHeader("*"); // 2 設置訪問源請求頭corsConfiguration.addAllowedMethod("*"); // 3 設置訪問源請求方法,或設置為"GET", "POST", "DELETE", "PUT"corsConfiguration.setMaxAge(MAX_AGE);source.registerCorsConfiguration("/**", corsConfiguration); // 4 對接口配置跨域設置return new CorsFilter(source);}
}
3,實現WebMvcConfigurer
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 WebConfig implements WebMvcConfigurer {// 當前跨域請求最大有效時長。這里默認1天private static final long MAX_AGE = 24 * 60 * 60;@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("*").allowedMethods("*").allowedHeaders("*").maxAge(MAX_AGE);}
}
4,Nginx解決跨域
如果項目中有使用Nginx來轉發請求,那也可以交由Nginx來解決跨域,但是有一點需要注意:Nginx解決跨域和后端解決跨域最好只保留一個,兩種混用會出現很多奇怪的問題。
下面是nginx.conf文件解決跨域的相關配置:
server {listen 80;server_name localhost;location / {if ($request_method = 'OPTIONS') {add_header Access-Control-Allow-Origin 'http://localhost:7060';add_header Access-Control-Allow-Headers '*';add_header Access-Control-Allow-Methods '*';add_header Access-Control-Allow-Credentials 'true';return 204;}if ($request_method != 'OPTIONS') {add_header Access-Control-Allow-Origin 'http://localhost:7060' always;add_header Access-Control-Allow-Credentials 'true';}proxy_pass http://localhost:59200; }}
5,注意
說明: 文章中很多地方為了方便,Access-Control-Allow-Origin設置成了*,這個在開發測試的時候可以這么設置,但如果是生產環境,建議不要設置成*,最好是允許哪些域名訪問就設置哪些,畢竟限制域名還是很有必要的。