跨域問題:CORS解決跨域原理
1.什麼是跨域問題?如圖
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的實作(這個一般不會采用,麻煩,每個控制器都得加)
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官方出品
spring:
cloud:
gateway:
globalcors:
corsConfigurations:
'[/**]':
allowedOrigins:
- "www.xxx.com" #允許跨域的域名
allowedHeaders:
- "*"
allowCredentials: true
maxAge: 360000
allowedMethods:
- GET
- POST
- DELETE
- PUT
- OPTIONS
- HEAD
想看更多精彩内容,可以關注我的部落格園
我的部落格園