跨域問題與SpringBoot解決方案

什麼是跨域?

定義:瀏覽器從一個域名的網頁取請求另外一個域名下的東西。通俗點說,瀏覽器直接從A域訪問B域中的資源是不被容許的,若是想要訪問,就須要進行一步操做,這操做就叫「跨域」。例如,你從百度的頁面,點擊一個按鈕,請求了新浪的一個接口,這就進行了跨域。不僅僅只有域名不一樣就是跨域,域名、端口、協議其一不一樣就是不一樣的域,請求資源須要跨域。跨域

爲何要跨域?

爲何須要跨域,而不直接訪問其餘域下的資源呢?這是瀏覽器的限制,專業點說叫瀏覽器同源策略限制。主要是爲了安全考慮。如今的安全框架,通常請求的時候header中不是都存個token嘛,你要是用這個token去正常訪問A域下的東西是沒問題的,而後又去訪問了B域,結果陰差陽錯的還帶着這個token,那麼B域,或者說B網站是否是就能夠拿着你的token去A域下作點什麼呢,這就至關危險了。因此瀏覽器加上了所謂的瀏覽器同源策略限制。可是爲了咱們真的須要從A域下訪問B的資源(正常訪問),就須要用到跨域,跨越這個限制了。瀏覽器

SpringBoot解決跨域問題

SpringBoot能夠基於Cors解決跨域問題,Cors是一種機制,告訴咱們的後臺,哪邊(origin )來的請求能夠訪問服務器的數據。安全

全局配置

配置實例以下:bash

@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源碼,十分簡單:cookie

public class CorsRegistry {

   private final List<CorsRegistration> registrations = new ArrayList<>();

   public CorsRegistration addMapping(String pathPattern) {
      CorsRegistration registration = new CorsRegistration(pathPattern);
      this.registrations.add(registration);
      return registration;
   }
   
   protected Map<String, CorsConfiguration> 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。app

回到示例代碼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這個註解,看看它是幹什麼的?ide

@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 = { "*" };

   /** @deprecated as of Spring 5.0, in favor of {@link CorsConfiguration#applyPermitDefaultValues} */
   @Deprecated
   String[] DEFAULT_ALLOWED_HEADERS = { "*" };

   /** @deprecated as of Spring 5.0, in favor of {@link CorsConfiguration#applyPermitDefaultValues} */
   @Deprecated
   boolean DEFAULT_ALLOW_CREDENTIALS = false;

   /** @deprecated as of Spring 5.0, in favor of {@link CorsConfiguration#applyPermitDefaultValues} */
   @Deprecated
   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解決跨域問題,能夠設置全局跨域,也能夠實現局部跨域,靈活配置方便使用。

相關文章
相關標籤/搜索