一、什麼是CORS
CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)。它允許瀏覽器向跨源服務器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。只要服務器實現了CORS接口,就可以跨源通信。
CORS有兩種請求,簡單請求和非簡單請求。
二、同源
跨域就等於從百度訪問谷歌的資源,URL由協議、域名、端口和路徑組成,如果兩個URL的協議、域名和端口相同,則表示他們同源。相反,只要協議
,域名
,端口
有任何一個的不同,就被當作是跨域。
瀏覽器採用同源策略,禁止頁面加載或執行與自身來源不同的域的任何腳本。
三、現象
假設在服務器8080和8088這2個端口同時掛載不同代碼
- 8088下代碼:
@RequestMapping ("/")
@ResponseBody
public String index(HttpServletResponse response) {
return "跨域內容顯示";
}
- 8080下代碼:
@RequestMapping("/cors")
public String cors(HttpServletResponse response) {
return "/cors";
}
cors.html
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<title></title>
<script th:src="@{js/jquery-1.9.1.min.js}"></script>
</head>
<body>
<button>獲取跨域內容</button>
<p id="p1"></p>
</body>
<script>
$(function(){
$("button").click(function(){
$.ajax({
type: "post",
url:"http://localhost:8088/",
success:function(result){
$("#p1").html(result);
}
});
});
});
</script>
</html>
直接訪問8088端口的方法時沒有任何問題
如果通過8080端口的ajaxa訪問8088的方法時,會報錯信息如下
Failed to load http://localhost:8088/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.
四、解決方案
被調用方需要的解決方案:
- SpringMVC中
public class CorsFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {
// CORS "pre-flight" request
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
response.addHeader("Access-Control-Max-Age", "1800");//30 min
}
//This will filter your requests and responses.
filterChain.doFilter(request, response);
}
}
web.xml
<filter>
<filter-name>allowedAccessFilter</filter-name>
<filter-class>aaa.bbb.ccc.ddd.CorsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>allowedAccessFilter</filter-name>
<url-pattern>/registeryuyue/*</url-pattern>
</filter-mapping>
- SpringBoot法一:
@SpringBootApplication
@Controller
@CrossOrigin (origins = "http://localhost:8080", maxAge = 3600)
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@RequestMapping ("/")
@ResponseBody
public String index(HttpServletResponse response) {
return "跨域內容顯示";
}
}
此方法中 CrossOrigin 註解只可以應用於單個controller,而下面全局配置的方式可以應用於整個工程
- SpringBoot法二:
package com.pzh.cros.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
/**
* 實現基本的跨域請求
*/
@Configuration
public class CorsConfig {
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setMaxAge(3600L); // 表明在3600秒內,不需要再發送預檢驗請求
corsConfiguration.addAllowedOrigin("http://localhost:8080"); // 允許http://localhost:8080域名使用
corsConfiguration.addAllowedHeader("*"); // 允許任何頭
corsConfiguration.addAllowedMethod("*"); // 允許任何方法(post、get等)
return corsConfiguration;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig()); // 對接口配置跨域設置
return new CorsFilter(source);
}
}
- Nginx配置
五、CORS常見的header
Access-Control-Allow-Origin: http://kbiao.me
Access-Control-Max-Age: 3628800
Access-Control-Allow-methods: GET, PUT, DELETE, POST
Access-Control-Allow-Header: content-type
Access-Control-Allow-Credentail: true
“Access-Control-Allow-Origin"表明它允許” http://kbiao.me "發起跨域請求
"Access-Control-Max-Age"表明在3628800秒內,不需要再發送預檢驗請求,可以緩存該結果(上面的資料上我們知道CROS協議中,一個AJAX請求被分成了第一步的OPTION預檢測請求和正式請求)
"Access-Control-Allow-Methods"表明它允許GET、PUT、DELETE的外域請求
"Access-Control-Allow-Headers"表明它允許跨域請求包含content-type頭
"Access-Control-Allow-Credentials"表明它允許cookies