跨域問題與SpringBoot解決方案
什麼是跨域?
定義:浏覽器從一個域名的網頁取請求另一個域名下的東西。通俗點說,浏覽器直接從A域通路B域中的資源是不被允許的,如果想要通路,就需要進行一步操作,這操作就叫“跨域”。例如,你從百度的頁面,點選一個按鈕,請求了新浪的一個接口,這就進行了跨域。不單單隻有域名不同就是跨域,域名、端口、協定其一不同就是不同的域,請求資源需要跨域。
為什麼要跨域?
為什麼需要跨域,而不直接通路其他域下的資源呢?這是浏覽器的限制,專業點說叫浏覽器同源政策限制。主要是為了安全考慮。現在的安全架構,一般請求的時候header中不是都存個token嘛,你要是用這個token去正常通路A域下的東西是沒問題的,然後又去通路了B域,結果陰差陽錯的還帶着這個token,那麼B域,或者說B網站是不是就可以拿着你的token去A域下做點什麼呢,這就相當危險了。是以浏覽器加上了所謂的浏覽器同源政策限制。但是為了我們真的需要從A域下通路B的資源(正常通路),就需要用到跨域,跨越這個限制了。
SpringBoot解決跨域問題
SpringBoot可以基于Cors解決跨域問題,Cors是一種機制,告訴我們的背景,哪邊(origin )來的請求可以通路伺服器的資料。
全局配置
配置執行個體如下:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.maxAge(3600);
}
}
首先實作了WebMvcConfigurer 接口,WebMvcConfigurer 這個接口十分強大,裡面還有很多可用的方法,在SpringBoot2.0裡面可以解決WebMvcConfigurerAdapter曾經的部分任務。其中一個方法就是addCorsMappings(),是專門為開發人員解決跨域而誕生的接口。其中構造參數為CorsRegistry。
看下CorsRegistry源碼,十分簡單:
public class CorsRegistry {
private final List registrations = new ArrayList<>();
public CorsRegistration addMapping(String pathPattern) {
CorsRegistration registration = new CorsRegistration(pathPattern);
this.registrations.add(registration);
return registration;
protected Map getCorsConfigurations() {
Map<String, CorsConfiguration> configs = new LinkedHashMap<>(this.registrations.size());
for (CorsRegistration registration : this.registrations) {
configs.put(registration.getPathPattern(), registration.getCorsConfiguration());
}
return configs;
}
可以看出CorsRegistry 有個屬性registrations ,按道理可以根據不同的項目路徑進行定制通路行為,但是我們示例直接将pathPattern 設定為 /**,也就是說已覆寫項目所有路徑,隻需要建立一個CorsRegistration就好。getCorsConfigurations(),這個方法是擷取所有CorsConfiguration的Map集合,key值為傳入路徑pathPattern。
回到示例代碼CorsConfig中,registry對象addMapping()增加完傳入路徑pathPattern之後,return了一個CorsRegistration對象,是進行更多的配置,看一下CorsRegistration的代碼,看看我們能配些什麼?
public class CorsRegistration {
//傳入的路徑
private final String pathPattern;
//配置資訊實體類
private final CorsConfiguration config;
//構造方法
public CorsRegistration(String pathPattern) {
this.pathPattern = pathPattern;
//原生注釋看到了一個 @CrossOrigin 這個注解,待會看看是什麼
// Same implicit default values as the @CrossOrigin annotation + allows simple methods
this.config = new CorsConfiguration().applyPermitDefaultValues();
//允許哪些源網站通路,預設所有
public CorsRegistration allowedOrigins(String... origins) {
this.config.setAllowedOrigins(Arrays.asList(origins));
return this;
//允許何種方式通路,預設簡單方式,即:GET,HEAD,POST
public CorsRegistration allowedMethods(String... methods) {
this.config.setAllowedMethods(Arrays.asList(methods));
return this;
//設定通路header,預設所有
public CorsRegistration allowedHeaders(String... headers) {
this.config.setAllowedHeaders(Arrays.asList(headers));
return this;
//設定response headers,預設沒有(什麼都不設定)
public CorsRegistration exposedHeaders(String... headers) {
this.config.setExposedHeaders(Arrays.asList(headers));
return this;
//是否浏覽器應該發送credentials,例如cookies Access-Control-Allow-Credentials
public CorsRegistration allowCredentials(boolean allowCredentials) {
this.config.setAllowCredentials(allowCredentials);
return this;
//設定等待時間,預設1800秒
public CorsRegistration maxAge(long maxAge) {
this.config.setMaxAge(maxAge);
return this;
protected String getPathPattern() {
return this.pathPattern;
protected CorsConfiguration getCorsConfiguration() {
return this.config;
局部配置
剛才遇到一個@CrossOrigin這個注解,看看它是幹什麼的?
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {
/* @deprecated as of Spring 5.0, in favor of {@link CorsConfiguration#applyPermitDefaultValues} /
@Deprecated
String[] DEFAULT_ORIGINS = { "*" };
String[] DEFAULT_ALLOWED_HEADERS = { "*" };
boolean DEFAULT_ALLOW_CREDENTIALS = false;
long DEFAULT_MAX_AGE = 1800
/**
* Alias for {@link #origins}.
*/
@AliasFor("origins")
String[] value() default {};
@AliasFor("value")
String[] origins() default {};
String[] allowedHeaders() default {};
String[] exposedHeaders() default {};
RequestMethod[] methods() default {};
String allowCredentials() default "";
long maxAge() default -1;
這個注解可以作用于方法或者類上,實作局部跨域,你會發現除了設定路徑(因為沒必要了,都定位到局部了)其他的參數與全局類似。
小結
SpringBoot可以基于Cors解決跨域問題,可以設定全局跨域,也可以實作局部跨域,靈活配置友善使用。
作者:Java_No2
來源:CSDN
原文:
https://blog.csdn.net/Java_No2/article/details/91612669版權聲明:本文為部落客原創文章,轉載請附上博文連結!