Spring Boot解決跨域的三種方案
一、了解源和跨域
源(origin)就是協議、域名和端口號。
URL由協議
、域名
、端口
和路徑
組成,如果兩個URL的協議、域名和端口全部相同,則表示他們同源。否則,只要協議、域名、端口有任何一個不同,就是跨域。
對https://www.baidu.com/index.html進行跨域比較:
URL | 是否跨域 | 原因 |
---|---|---|
https://www.baidu.com/more/index.html | 不跨域 | 三要素相同 |
https://map.baidu.com/ | 跨域 | 域名不同 |
http://www.baidu.com/index.html | 跨域 | 協議不同 |
https://www.baidu.com:81/index.html | 跨域 | 端口號不同 |
二、同源策略
同源策略(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會受到影響。可以說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現。
同源策略又分為以下兩種:
- DOM同源策略:禁止對不同源頁面DOM 進行操作。這里主要場景是iframe跨域的情況,不同域名的iframe是限制互相訪問的。
- XMLHttpRequest同源策略:禁止使用XHR對象向不同源的服務器地址發起HTTP請求。
同源策略限制了從同一個源加載的文檔或腳本如何與來自另一個源的資源進行交互。這是一個用於隔離潛在惡意文件的重要安全機制。
三、CROS (Cross-origin resource sharing)
CORS是一個W3C標准,全稱是"跨域資源共享”(Cross-origin resource sharing)。
它允許瀏覽器向跨源(協議 + 域名 + 端口)服務器,發出XMLHttpRequest
請求,從而克服了AJAX只能同源使用的限制。CORS需要瀏覽器和服務器同時支持。它的通信過程,都是瀏覽器自動完成,不需要用戶參與。
對於開發者來說,CORS通信與同源的AJAX/Fetch通信沒有差別,代碼完全一樣。瀏覽器一旦發現請求跨源,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會有感覺。因此,實現CORS通信的關鍵是服務器。只要服務器實現了CORS接口,就可以跨源通信。
CORS Header
- Access-Control-Allow-Origin: http://www.xxx.com
- Access-Control-Max-Age:86400
- Access-Control-Allow-Methods:GET, POST, OPTIONS, PUT, DELETE
- Access-Control-Allow-Headers: content-type
- Access-Control-Allow-Credentials: true
含義解釋:
CORS Header屬性 | 解釋 |
---|---|
Access-Control-Allow-Origin | 允許http://www.xxx.com域(自行設置,這里只做示例)發起跨域請求 |
Access-Control-Max-Age | 設置在86400秒不需要再發送預校驗請求 |
Access-Control-Allow-Methods | 設置允許跨域請求的方法 |
Access-Control-Allow-Headers | 允許跨域請求包含content-type |
Access-Control-Allow-Credentials | 設置允許Cookie |
四、Spring Boot解決跨域
- 方法一 實現
WebMvcConfigurer
接口
增加一個配置類,CrossOriginConfig.java。繼承WebMvcConfigurerAdapter或者實現WebMvcConfigurer接口。WebMvcConfigurerAdapter現在大多數已啟用 因為Spring
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(true)
.maxAge(3600)
.allowedHeaders("*");
}
}
WebMvcConfigurerAdapter 在spring5.0已經被標記為Deprecated,Spring5最低支持到jdk1.8,所以可以直接實現WebMvcConfigurer接口,無需再用這個適配器,因為jdk1.8支持接口中存在default-method。
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* AJAX請求跨域
* @author Mr.W
* @time 2018-08-13
*/
@Configuration
public class CorsConfig extends WebMvcConfigurerAdapter {
static final String ORIGINS[] = new String[] { "GET", "POST", "PUT", "DELETE" };
@Override
public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**").allowedOrigins("*").allowCredentials(true).allowedMethods(ORIGINS).maxAge(3600);
}
- 方法二 : 采用過濾器(Filter)的方式
import org.springframework.context.annotation.Configuration;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(filterName = "CorsFilter ")
@Configuration
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin","*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
chain.doFilter(req, res);
}
}
- 方法三: @CrossOrigin注解
在Controller公共父類(BaseController)中,所有Controller繼承即可, 這樣就不需要每個Controller甚至方法上都加這個注解。
@CrossOrigin
public class BaseController {
}
@RestController
public class PayController extend BaseController {
}