SpringBoot:CORS處理跨域請求的三種方式


一、跨域背景

1.1 何為跨域?

Url的一般格式:

協議 + 域名(子域名 + 主域名) + 端口號 + 資源地址

示例:

https://www.dustyblog.cn:8080/say/Hello 是由

https + www + dustyblog.cn + 8080 + say/Hello 組成

 

組成。

只要協議,子域名,主域名,端口號這四項組成部分中有一項不同,就可以認為是不同的域,不同的域之間互相訪問資源,就被稱之為跨域。

1.2 一次正常的請求

  • Controller層代碼:
1 @RequestMapping("/demo")
2 @RestController
3 public class CorsTestController {
4 
5     @GetMapping("/sayHello")
6     public String sayHello() {
7         return "hello world !";
8     }
9 }
  • 啟動項目,測試請求

    瀏覽器打開localhost:8080/demo/sayHello

     可以打印出“hello world”

1.3 跨域測試

以Chrome為例:

  • 打開任意網站,如:https://blog.csdn.net

  • 按F12,打開【開發者工具】,在里面的【Console】可以直接輸入js代碼測試;

var token= "LtSFVqKxvpS1nPARxS2lpUs2Q2IpGstidMrS8zMhNV3rT7RKnhLN6d2FFirkVEzVIeexgEHgI/PtnynGqjZlyGkJa4+zYIXxtDMoK/N+AB6wtsskYXereH3AR8kWErwIRvx+UOFveH3dgmdw1347SYjbL/ilGKX5xkoZCbfb1f0=,LZkg22zbNsUoHAgAUapeBn541X5OHUK7rLVNHsHWDM/BA4DCIP1f/3Bnu4GAElQU6cds/0fg9Li5cSPHe8pyhr1Ii/TNcUYxqHMf9bHyD6ugwOFTfvlmtp6RDopVrpG24RSjJbWy2kUOOjjk5uv6FUTmbrSTVoBEzAXYKZMM2m4=,R4QeD2psvrTr8tkBTjnnfUBw+YR4di+GToGjWYeR7qZk9hldUVLlZUsEEPWjtBpz+UURVmplIn5WM9Ge29ft5aS4oKDdPlIH8kWNIs9Y3r9TgH3MnSUTGrgayaNniY9Ji5wNZiZ9cE2CFzlxoyuZxOcSVfOxUw70ty0ukLVM/78=";
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://127.0.0.1:8080/demo/sayHello');
xhr.setRequestHeader("x-access-token",token);
xhr.send(null);
xhr.onload = function(e) {
    var xhr = e.target;
    console.log(xhr.responseText);
}

 該結果表明:該請求在https://blog.csdn.net域名下請求失敗!

二、解決方案 - Cors跨域

2.1 Cors是什么

CORS全稱為Cross Origin Resource Sharing(跨域資源共享), 每一個頁面需要返回一個名為Access-Control-Allow-Origin的http頭來允許外域的站點訪問,你可以僅僅暴露有限的資源和有限的外域站點訪問。

 我們可以理解為:如果一個請求需要允許跨域訪問,則需要在http頭中設置

Access-Control-Allow-Origin來決定需要允許哪些站點來訪問。如假設需要允許https://www.dustyblog.c這個站點的請求跨域,則可以設置:

Access-Control-Allow-Origin:https://www.dustyblog.cn。

2.2 如何解決Cors跨域

   2.2.1方案一:使用@CrossOrigin注解

     在Controller上使用@CrossOrigin注解,該類下的所有接口都可以通過跨域訪問

 1 @RequestMapping("/demo2")
 2 @RestController
 3 //@CrossOrigin //所有域名均可訪問該類下所有接口
 4 @CrossOrigin("https://blog.csdn.net") // 只有指定域名可以訪問該類下所有接口
 5 public class CorsTest2Controller {
 6 
 7     @GetMapping("/sayHello")
 8     public String sayHello() {
 9         return "hello world --- 2";
10     }
11 }

   這里指定當前的CorsTest2Controller中所有的方法可以處理https://csdn.net域上的請求,這里可以測試一下:

  • https://blog.csdn.net頁面打開調試窗口,輸入(注意:這里請求地址是/demo2,請區別於1.2 案例中的/demo)
var token= "LtSFVqKxvpS1nPARxS2lpUs2Q2IpGstidMrS8zMhNV3rT7RKnhLN6d2FFirkVEzVIeexgEHgI/PtnynGqjZlyGkJa4+zYIXxtDMoK/N+AB6wtsskYXereH3AR8kWErwIRvx+UOFveH3dgmdw1347SYjbL/ilGKX5xkoZCbfb1f0=,LZkg22zbNsUoHAgAUapeBn541X5OHUK7rLVNHsHWDM/BA4DCIP1f/3Bnu4GAElQU6cds/0fg9Li5cSPHe8pyhr1Ii/TNcUYxqHMf9bHyD6ugwOFTfvlmtp6RDopVrpG24RSjJbWy2kUOOjjk5uv6FUTmbrSTVoBEzAXYKZMM2m4=,R4QeD2psvrTr8tkBTjnnfUBw+YR4di+GToGjWYeR7qZk9hldUVLlZUsEEPWjtBpz+UURVmplIn5WM9Ge29ft5aS4oKDdPlIH8kWNIs9Y3r9TgH3MnSUTGrgayaNniY9Ji5wNZiZ9cE2CFzlxoyuZxOcSVfOxUw70ty0ukLVM/78=";
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://127.0.0.1:8080/demo2/sayHello');
xhr.setRequestHeader("x-access-token",token);
xhr.send(null);
xhr.onload = function(e) {
    var xhr = e.target;
    console.log(xhr.responseText);
}

  返回結果:

ƒ (e) {
    var xhr = e.target;
    console.log(xhr.responseText);
}
VM156:8 hello world --- 2

說明跨域成功!

  • 換個域名測試一下看跨域是否還有效,在https://www.baidu.com按照上述方法測試一下,返回結果:
OPTIONS http://127.0.0.1:8080/demo2/sayHello 403
(anonymous)
Access to XMLHttpRequest at 'http://127.0.0.1:8080/demo2/sayHello' 
from origin 'http://www.cnblogs.com' has been blocked by CORS policy: 
Response to preflight request doesn't pass access control check: 
No 'Access-Control-Allow-Origin' header is present on the requested resource.

     說明跨域失敗!證明該方案成功指定了部分域名能跨域!

  2.2.2方案二: CORS全局配置-實現WebMvcConfigurer

  • 新建跨域配置類:CorsConfig.java:
 1 /**
 2  * 跨域配置
 3  */
 4 @Configuration
 5 public class CorsConfig implements WebMvcConfigurer {
 6 
 7     @Bean
 8     public WebMvcConfigurer corsConfigurer()
 9     {
10         return new WebMvcConfigurer() {
11             @Override
12             public void addCorsMappings(CorsRegistry registry) {
13                 registry.addMapping("/**").
14                         allowedOrigins("https://www.dustyblog.cn"). //允許跨域的域名,可以用*表示允許任何域名使用
15                         allowedMethods("*"). //允許任何方法(post、get等)
16                         allowedHeaders("*"). //允許任何請求頭
17                         allowCredentials(true). //帶上cookie信息
18                         exposedHeaders(HttpHeaders.SET_COOKIE).maxAge(3600L); //maxAge(3600)表明在3600秒內,不需要再發送預檢驗請求,可以緩存該結果
19             }
20         };
21     }
22 }
  • 測試,在允許訪問的域名https://www.dustyblog.cn/控制台輸入(注意,這里請求的是http://127.0.0.1:8080/demo3):
var token= "LtSFVqKxvpS1nPARxS2lpUs2Q2IpGstidMrS8zMhNV3rT7RKnhLN6d2FFirkVEzVIeexgEHgI/PtnynGqjZlyGkJa4+zYIXxtDMoK/N+AB6wtsskYXereH3AR8kWErwIRvx+UOFveH3dgmdw1347SYjbL/ilGKX5xkoZCbfb1f0=,LZkg22zbNsUoHAgAUapeBn541X5OHUK7rLVNHsHWDM/BA4DCIP1f/3Bnu4GAElQU6cds/0fg9Li5cSPHe8pyhr1Ii/TNcUYxqHMf9bHyD6ugwOFTfvlmtp6RDopVrpG24RSjJbWy2kUOOjjk5uv6FUTmbrSTVoBEzAXYKZMM2m4=,R4QeD2psvrTr8tkBTjnnfUBw+YR4di+GToGjWYeR7qZk9hldUVLlZUsEEPWjtBpz+UURVmplIn5WM9Ge29ft5aS4oKDdPlIH8kWNIs9Y3r9TgH3MnSUTGrgayaNniY9Ji5wNZiZ9cE2CFzlxoyuZxOcSVfOxUw70ty0ukLVM/78=";
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://127.0.0.1:8080/demo3/sayHello');
xhr.setRequestHeader("x-access-token",token);
xhr.send(null);
xhr.onload = function(e) {
    var xhr = e.target;
    console.log(xhr.responseText);
}

  返回結果:

ƒ (e) {
    var xhr = e.target;
    console.log(xhr.responseText);
}
VM433:8 hello world --- 3

 說明跨域成功,換個網址如https://www.baidu.com測試依舊出現需要跨域的錯誤提示,證明該配置正確,該方案測試通過。

  2.2.3方案三:攔截器Filter實現

  通過實現Fiter接口在請求中添加一些Header來解決跨域的問題

 1 @Component
 2 public class CorsFilter implements Filter {
 3 
 4     @Override
 5     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
 6             throws IOException, ServletException {
 7         HttpServletResponse res = (HttpServletResponse) response;
 8         res.addHeader("Access-Control-Allow-Credentials", "true");
 9         res.addHeader("Access-Control-Allow-Origin", "*");
10         res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
11         res.addHeader("Access-Control-Allow-Headers", "Content-Type,X-CAF-Authorization-Token,sessionToken,X-TOKEN");
12         if (((HttpServletRequest) request).getMethod().equals("OPTIONS")) {
13             response.getWriter().println("ok");
14             return;
15         }
16         chain.doFilter(request, response);
17     }
18     @Override
19     public void destroy() {
20     }
21     @Override
22     public void init(FilterConfig filterConfig) throws ServletException {
23     }
24 }

 至此,跨域請求就完成了,有更多更好方法的朋友歡迎留言!

 好文轉轉學習自:https://www.cnblogs.com/vandusty/p/11408422.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM