天天看點

跨域問題:CORS解決跨域原理

跨域問題:CORS解決跨域原理

1.什麼是跨域問題?如圖

跨域問題:CORS解決跨域原理

1.1跨域問題需要滿足以下條件

1.1.1 跨域

域名不同,域名相同,端口不同或者二級域名不同

1.1.2 是針對ajax的一種限制

跨域問題是浏覽器對于ajax請求的一種安全限制:一個頁面發起的ajax請求,隻能是于目前頁同域名的路徑,這能有效的阻止跨站攻擊

2.怎麼解決跨域問題

2.1目前比較常用的跨域解決方案有3種:

Jsonp

最早的解決方案,利用script标簽可以跨域的原理實作。

限制:

需要服務的支援

隻能發起GET請求

nginx反向代理

思路是:利用nginx反向代理把跨域為不跨域,支援各種請求方式

缺點:需要在nginx進行額外配置,語義不清晰

CORS

規範化的跨域請求解決方案,安全可靠。

優勢:

在服務端進行控制是否允許跨域,可自定義規則

支援各種請求方式

3.CORS解決跨域

3.1什麼是CORS

3.1.1CORS允許浏覽器向跨源伺服器,發出XMLHttpRequest請求,進而克服了AJAX隻能同源使用的限制

浏覽器端:

目前,所有浏覽器都支援該功能(IE10以下不行)。整個CORS通信過程,都是浏覽器自動完成,不需要使用者參與。

服務端:

CORS通信與AJAX沒有任何差别,是以你不需要改變以前的業務邏輯。隻不過,浏覽器會在請求中攜帶一些頭資訊,我們需要以此判斷是否允許其跨域,然後在響應頭中加入一些資訊即可。這一般通過過濾器完成即可。

3.2實作原理

浏覽器會将ajax請求分為兩類,其處理方案略有差異:簡單請求、特殊請求。

3.1簡單請求 =>(請求方法:HEAD、GET、POST)

3.1.1解決:在請求頭中攜帶一個字段:Origin

Origin中會指出目前請求屬于哪個域(協定+域名+端口)。服務會根據這個值決定是否允許其跨域

如果伺服器允許跨域,需要在傳回的響應頭中攜帶下面資訊:

Access-Control-Allow-Origin: 允許跨域的域名

Access-Control-Allow-Credentials: true

3.2特殊請求=>(不符合簡單請求的會被浏覽器判定為特殊請求,,例如請求方式為PUT)

如果是特殊請求産生的跨域會先發起一次OPTIONS預檢請求,如果預檢請求通過了,才會發送真正的請求。

特殊請求會在正式通信之前,增加一次HTTP查詢請求,稱為"預檢"請求(preflight)。

浏覽器先詢問伺服器,目前網頁所在的域名是否在伺服器的許可名單之中,以及可以使用哪些HTTP動詞和頭資訊字段。隻有得到肯定答複,浏覽器才會發出正式的XMLHttpRequest請求,否則就報錯。

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

Access-Control-Request-Method:接下來會用到的請求方式,比如PUT

Access-Control-Request-Headers:會額外用到的頭資訊

4.CORS解決跨域方式

4.1方式一:隻需要在controller類上添加注解@CrossOrigin 即可!這個注解其實是CORS的實作(這個一般不會采用,麻煩,每個控制器都得加)

跨域問題:CORS解決跨域原理

4.3方式二:在攔截器配置(推薦)

package cn.mindgd.config;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;

public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //表示接受任意域名的請求,也可以指定域名
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("origin"));

        //該字段可選,是個布爾值,表示是否可以攜帶cookie
        response.setHeader("Access-Control-Allow-Credentials", "true");

        response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS");

        response.setHeader("Access-Control-Allow-Headers", "*");


        return true;

    }
}
           
package cn.mindgd.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 攔截器配置
 */
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {


    @Bean
    AuthInterceptor corsInterceptor() {
        return new AuthInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        /**
         * 攔截全部路徑,這個跨域需要放在最上面
         */
        registry.addInterceptor(corsInterceptor()).addPathPatterns("/**");

        WebMvcConfigurer.super.addInterceptors(registry);

    }

}
           

4.2方式三:在網關解決,SpringCloudGateway是Spring官方出品

跨域問題:CORS解決跨域原理
spring:
  cloud:
    gateway:
      globalcors:
        corsConfigurations:
          '[/**]':
            allowedOrigins:
              - "www.xxx.com" #允許跨域的域名
            allowedHeaders:
              - "*"
            allowCredentials: true
            maxAge: 360000
            allowedMethods:
              - GET
              - POST
              - DELETE
              - PUT
              - OPTIONS
              - HEAD
           

想看更多精彩内容,可以關注我的部落格園

我的部落格園