springboot系列六 cors跨域支持

CORS理解

CORS(Cross-Origin Resource Sharing) 跨域資源共享
瀏覽器在訪問當前域名下的資源時,能直接傳輸數據。可是出於安全考慮,瀏覽器在訪問非當前域名的資源時會遇到跨域訪問限制
這時候咱們須要一種機制:跨域資源共享(cors)

cors的請求類型

來自 CORS簡介(做者 loveis715)javascript

簡單請求(Simple Request)

若是一個請求沒有包含任何自定義請求頭,並且它所使用HTTP動詞是GET,HEAD或POST之一,那麼它就是一個Simple Request。可是在使用POST做爲請求的動詞時,該請求的Content-Type須要是application/x-www-form-urlencoded,multipart/form-data或text/plain之一。

預檢請求(Preflighted Request)

若是一個請求包含了任何自定義請求頭,或者它所使用的HTTP動詞是GET,HEAD或POST以外的任何一個動詞,那麼它就是一個Preflighted Request。若是POST請求的Content-Type並非application/x-www-form-urlencoded,multipart/form-data或text/plain之一,那麼其也是Preflighted Request。

帶憑證的請求(Requests with Credential)

通常狀況下,一個跨域請求不會包含當前頁面的用戶憑證。一旦一個跨域請求包含了當前頁面的用戶憑證,那麼其就屬於Requests with Credential。

springboot的cors支持

場景

springboot提供api服務(端口8080),前端經過jquery發送http請求(端口63342),因爲端口不一樣,會形成跨域訪問

代碼

springboot接口css

@GetMapping("/api/cors/get")
    public String get(){
        return "cors test get method";
    }
@PostMapping("/api/cors/post")
    public String post(){
        return "cors test post method";
    }

前端代碼:cors.htmlhtml

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>cors跨域測試</title>
    <script src="https://cdn.bootcss.com/jquery/2.1.0/jquery.min.js"></script>
    <script type="text/javascript">
        function crosGet(){
            $.ajax({
                type:'get',
                url:'http://localhost:8080/api/cors/get',
                dateType: 'json',
                data:{},
                success: function (data) {
                    $("#getRes").html('請求成功。' + data);
                },
                error: function (data) {
                    console.log('請求失敗:' + data);
                    $("#getRes").html('請求失敗!!!' + JSON.stringify(data));
                }
            });
        }

        function crosPost(){
            $.ajax({
                type:'post',
                url:'http://localhost:8080/api/cors/post',
                dateType: 'json',
                data:{},
                success: function (data) {
                    $("#postRes").html('請求成功。' + data);
                },
                error: function (data) {
                    $("#postRes").html('請求失敗!!!' + JSON.stringify(data));
                }
            });
        }
    </script>
</head>
<body>
<button onclick="crosGet()">get跨域測試</button>
<div id="getRes" style="width:80%;height:50px;background-color:#ccc;"></div>
<hr/>
<button onclick="crosPost()">post跨域測試</button>
<div id="postRes" style="width:80%;height:50px;background-color:#ccc;"></div>
</body>
</html>

前端代碼cors.html能夠放到tomcat或者nginx中,這裏直接使用idea的open in Browser打開,默認端口爲63342前端

不容許非當前域名訪問錯誤

啓動sprinboot後,點擊前端按鈕測試,會返回錯誤:java

Access to XMLHttpRequest at 'http://localhost:8080/api/cors/get' from origin 'http://localhost:63342' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
當前域名:http://localhost:63342
要訪問的域名:http://localhost:8080
錯誤緣由:發生了跨域訪問,服務端(8080)未容許該域名(63342)進行訪問

添加cors支持,容許域名訪問

springboot中,添加cors支持的配置:jquery

@Configuration
public class CorsConfig {
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/api/**")
                        .allowedOrigins("http://localhost:63342");//容許域名訪問,若是*,表明全部域名
            }
        };
    }
}

再次測試,成功nginx

header跨域限制

修改配置,只容許header中帶Authorization或者Token的請求訪問git

@Configuration
public class CorsConfig {
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/api/**")
                        .allowedHeaders("Authorization", "Token")//容許的頭信息
                        .allowedOrigins("http://localhost:63342");
            }
        };
    }
}

修改html中,post接口header帶Authorization,get接口header帶aaaajax

function crosGet(){
            $.ajax({
                type:'get',
                url:'http://localhost:8080/api/cors/get',
                dateType: 'json',
                data:{},
                headers:{'aaa':'Basic 123456'},
                success: function (data) {
                    $("#getRes").html('請求成功。' + data);
                },
                error: function (data) {
                    console.log('請求失敗:' + data);
                    $("#getRes").html('請求失敗!!!' + JSON.stringify(data));
                }
            });
        }
function crosPost(){
            $.ajax({
                type:'post',
                url:'http://localhost:8080/api/cors/post',
                dateType: 'json',
                data:{},
                //headers:{'Authorization':'Basic 123456'},//帶頭信息方式1
                beforeSend: function (xhr) {
                    xhr.setRequestHeader('Authorization','Basic 123456');//帶頭信息方式2
                },
                success: function (data) {
                    $("#postRes").html('請求成功。' + data);
                },
                error: function (data) {
                    console.log('請求失敗:' + data);
                    $("#postRes").html('請求失敗!!!' + JSON.stringify(data));
                }
            });
        }

測試,get訪問失敗,post成功spring

請求方式限制

修改配置,只支持post方式訪問:

@Configuration
public class CorsConfig {
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/api/**")
                        .allowedHeaders("Authorization", "Token")
                        .allowedMethods("POST")//只容許post方式
                        .allowedOrigins("http://localhost:63342");
            }
        };
    }
}

測試,get訪問失敗,post成功

配置get和post都容許,則都訪問成功

egistry.addMapping("/api/**")
                        .allowedMethods("GET", "POST")

局部跨域設置

上面是配置了全局的跨域訪問,也能夠配置局部訪問控制

類上面註解@CrossOrigin

@CrossOrigin(origins = "http://domain.com", allowedHeaders = "token", methods = {RequestMethod.GET, RequestMethod.POST})
@RestController
public class TestResource{

}

方法上面的@CrossOrigin

@RestController
public class TestResource{
    @CrossOrigin(origins = "http://domain.com", allowedHeaders = {"header1", "header2"})
    @GetMapping("/api/test")
    public String test(){
        return "test";
    }
}

CORS參考文檔

CORS簡介(做者 loveis715)

moz技術文檔 HTTP訪問控制(CORS)

springboot官方文檔

源碼地址

https://gitee.com/yimingkeji/springboot/tree/master/cors

相關文章
相關標籤/搜索