【SpringBoot教程】SpringBoot 實現前后端分離的跨域訪問(CORS)

作者簡介:大家好,我是擼代碼的羊駝,前阿里巴巴架構師,現某互聯網公司CTO

聯系v:sulny_ann(17362204968),加我進群,大家一起學習,一起進步,一起對抗互聯網寒冬

# 序言

跨域資源共享向來都是熱門的需求,使用CORS可以幫助我們快速實現跨域訪問,只需在服務端進行授權即可,無需在前端添加額外設置,比傳統的JSONP跨域更安全和便捷。

一、基本介紹

簡單來說,CORS是一種訪問機制,英文全稱是Cross-Origin Resource Sharing,即我們常說的跨域資源共享,通過在服務器端設置響應頭,把發起跨域的原始域名添加到Access-Control-Allow-Origin 即可。

1. CORS工作原理

CORS實現跨域訪問并不是一蹴而就的,需要借助瀏覽器的支持,從原理題圖我們可以清楚看到,簡單的請求(通常指GET/POST/HEAD方式,并沒有去增加額外的請求頭信息)直接創建了跨域請求的XHR對象,而復雜的請求則要求先發送一個"預檢"請求,待服務器批準后才能真正發起跨域訪問請求。

來自維基百科

根據官方文檔W3C規范-CORS?的描述,目前CORS使用了如下頭部信息:

2. Request Headers(請求頭)

溫馨提示:Request Headers 無需人為干預,因為瀏覽器會自動識別跨域請求并添加對應的請求頭。

  • Origin 表示發起跨域請求的原始域。

  • Access-Control-Request-Method 表示發起跨域請求的方式,例如GET/POST。

  • Access-Control-Request-Headers表示發起跨域請求的額外頭信息。

3. Response headers(響應頭 )

溫馨提示:Response Headers 需要人為干預,通過設置響應頭以幫助服務器資源進行跨域授權,例如允許哪些原始域進行跨域請求,是否允許響應信息攜帶Cookie等認證信息。

  • Access-Control-Allow-Origin 表示允許哪些原始域進行跨域訪問。

  • Access-Control-Allow-Credentials表示是否允許客戶端獲取用戶憑據。

使用場景:例如現在需要登錄系統后才能發起跨域請求,并且要附帶Cookie信息給服務器。則必須具備兩個條件:

1. 瀏覽器端:發送AJAX請求前需設置通信對象XHR的withCredentials 屬性為true。

2.服務器端:設置Access-Control-Allow-Credentials為true。兩個條件缺一不可,否則即使服務器同意發送Cookie,瀏覽器也無法獲取。

正確姿勢如下:

$.ajax({    url: 'localhost:8080',    xhrFields: {        withCredentials: true //表示發起跨域訪問并要求攜帶Cookie等認證信息    },    success: function (r) {        console.log(r)    }});
 

有好奇的小伙伴可能會問為什么在W3C手冊中找不到跨域屬性xhrFields的描述,因為該屬性并不是通信對象XHR的默認屬性,而是自定義屬性,所以在jQuery Ajax 參考手冊?中并沒有明確注明,但我們可以在jQuery源碼中找到這段蛛絲馬跡,那么整體思路就很清晰了。

???????

// Cross domain only allowed if supported through XMLHttpRequest    if ( support.cors || xhrSupported && !options.crossDomain ) {        return {            send: function( headers, complete ) {                var i,                    xhr = options.xhr();
                xhr.open(                    options.type,                    options.url,                    options.async,                    options.username,                    options.password                );
                // Apply custom fields if provided                if ( options.xhrFields ) {                    for ( i in options.xhrFields ) {                        xhr[ i ] = options.xhrFields[ i ];                    }                }           ...    }
 
  • Access-Control-Allow-Methods 表示允許哪些跨域請求的提交方式。(例如GET/POST)

  • Access-Control-Allow-Headers ?表示跨域請求的頭部的允許范圍。

  • Access-Control-Expose-Headers 表示允許暴露哪些頭部信息給客戶端。

    使用說明:基于安全考慮,如果沒有設置額外的暴露,跨域的通信對象XMLHttpRequest只能獲取標準的頭部信息。

  • Access-Control-Max-Age 表示預檢請求 [Preflight Request] 的最大緩存時間。

二、CORS實現跨域訪問

授權方式

  • 方式1:返回新的CorsFilter

  • 方式2:重寫WebMvcConfigurer

  • 方式3:使用注解(@CrossOrigin)

  • 方式4:手工設置響應頭(HttpServletResponse )

注:CorsFilter / WebMvcConfigurer / @CrossOrigin 需要SpringMVC 4.2 以上的版本才支持,對應SpringBoot 1.3 版本以上都支持這些CORS特性。不過,使用SpringMVC4.2 以下版本的小伙伴也不用慌,直接使用方式4通過手工添加響應頭來授權CORS跨域訪問也是可以的。附:在SpringBoot 1.2.8 + SpringMVC 4.1.9 親測成功。

注:方式1和方式2屬于全局CORS配置,方式3和方式4屬于局部CORS配置。如果使用了局部跨域是會覆蓋全局跨域的規則,所以可以通過@CrossOrigin注解來進行細粒度更高的跨域資源控制。

1. 返回新的CorsFilter(全局跨域)

在任意配置類,返回一個新的CorsFilter Bean,并添加映射路徑和具體的CORS配置信息。

???????

package com.hehe.yyweb.config;
@Configurationpublic class GlobalCorsConfig {    @Bean    public CorsFilter corsFilter() {        //1.添加CORS配置信息        CorsConfiguration config = new CorsConfiguration();          //放行哪些原始域          config.addAllowedOrigin("*");          //是否發送Cookie信息          config.setAllowCredentials(true);          //放行哪些原始域(請求方式)          config.addAllowedMethod("*");          //放行哪些原始域(頭部信息)          config.addAllowedHeader("*");          //暴露哪些頭部信息(因為跨域訪問默認不能獲取全部頭部信息)          config.addExposedHeader("*");
        //2.添加映射路徑        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();        configSource.registerCorsConfiguration("/**", config);
        //3.返回新的CorsFilter.        return new CorsFilter(configSource);    }}

 

2. 重寫WebMvcConfigurer(全局跨域)

在任意配置類,返回一個新的WebMvcConfigurer Bean,并重寫其提供的跨域請求處理的接口,目的是添加映射路徑和具體的CORS配置信息。

???????

package com.hehe.yyweb.config;
@Configurationpublic class GlobalCorsConfig {    @Bean    public WebMvcConfigurer corsConfigurer() {        return new WebMvcConfigurer() {            @Override            //重寫父類提供的跨域請求處理的接口            public void addCorsMappings(CorsRegistry registry) {                //添加映射路徑                registry.addMapping("/**")                        //放行哪些原始域                        .allowedOrigins("*")                        //是否發送Cookie信息                        .allowCredentials(true)                        //放行哪些原始域(請求方式)                        .allowedMethods("GET","POST", "PUT", "DELETE")                        //放行哪些原始域(頭部信息)                        .allowedHeaders("*")                        //暴露哪些頭部信息(因為跨域訪問默認不能獲取全部頭部信息)                        .exposedHeaders("Header1", "Header2");            }        };    }}
 

3. 使用注解(局部跨域)

在方法上(@RequestMapping)使用注解 @CrossOrigin :

???????

    @RequestMapping("/hello")    @ResponseBody    @CrossOrigin("http://localhost:8080")     public String index( ){        return "Hello World";    }
 

或者在控制器(@Controller)上使用注解 @CrossOrigin :

???????

@Controller@CrossOrigin(origins = "http://xx-domain.com", maxAge = 3600)public class AccountController {
    @RequestMapping("/hello")    @ResponseBody    public String index( ){        return "Hello World";    }}
 

4. 手工設置響應頭(局部跨域 )

使用HttpServletResponse對象添加響應頭(Access-Control-Allow-Origin)來授權原始域,這里Origin的值也可以設置為"*" ,表示全部放行。

???????

    @RequestMapping("/hello")    @ResponseBody    public String index(HttpServletResponse response){        response.addHeader("Access-Control-Allow-Origin", "http://localhost:8080");        return "Hello World";    }
 

三、測試跨域訪問

首先使用?Spring Initializr?快速構建一個Maven工程,什么都不用改,在static目錄下,添加一個頁面:index.html 來模擬跨域訪問。

???????

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8"/>    <title>Page Index</title></head><body><h2>前臺系統</h2><p id="info"></p></body><script src="webjars/jquery/3.2.1/jquery.js"></script><script>    $.ajax({        url: 'http://localhost:8090/hello',        type: "POST",        xhrFields: {           withCredentials: true //允許跨域認證        },        success: function (data) {            $("#info").html("跨域訪問成功:"+data);        },        error: function (data) {            $("#info").html("跨域失敗!!");        }    })</script></html>
 

然后創建另一個工程,在Root Package添加Config目錄并創建配置類來開啟全局CORS。

???????

package com.hehe.yyweb.config;
@Configurationpublic class GlobalCorsConfig {
    @Bean    public WebMvcConfigurer corsConfigurer() {        return new WebMvcConfigurer() {            @Override            public void addCorsMappings(CorsRegistry registry) {                registry.addMapping("/**");            }        };    }}
 

接著,簡單編寫一個Rest接口 ,并指定應用端口為8090。

???????

package com.hehe.yyweb;
@SpringBootApplication@RestControllerpublic class YyWebApplication {
    @Bean    public TomcatServletWebServerFactory tomcat() {        TomcatServletWebServerFactory tomcatFactory = new TomcatServletWebServerFactory();        tomcatFactory.setPort(8090); //默認啟動8090端口        return tomcatFactory;    }
    @RequestMapping("/hello")    public String index() {        return "Hello World";    }
    public static void main(String[] args) {        SpringApplication.run(YyWebApplication.class, args);    }}
 

最后分別啟動兩個應用,然后在瀏覽器訪問:http://localhost:8080/index.html?,可以正常接收JSON數據,說明跨域訪問成功!!

嘗試把全局CORS關閉,或者沒有單獨在方法或類上授權跨域,再次訪問:http://localhost:8080/index.html?時會看到跨域請求失敗!!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/213637.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/213637.shtml
英文地址,請注明出處:http://en.pswp.cn/news/213637.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【畢業季|進擊的技術er】作為一名職場人,精心總結的嵌入式學習路線圖

活動地址&#xff1a;畢業季進擊的技術er 文章目錄 0、作者介紹1、前言2、嵌入式基礎必備知識2.1、學習內容2.2、學習建議2.3、學習資料 3、嵌入式入門篇——51單片機3.1、學習內容3.2、學習建議3.3、學習資料 4、STM32進階篇4.1、學習內容4.2、學習建議4.3、學習資料 5、小而美…

印刷包裝企業做什么認證才有優勢

最近幾年&#xff0c;外貿出口過程中&#xff0c;越來越多的印刷和包裝企業被客戶要求進行各類認證和審核&#xff0c;比如&#xff0c;產品印刷包裝&#xff0f;吊牌等。他們已經意識到&#xff0c;印刷包裝供應商對于整個供應鏈管理的重要性&#xff0c;尤其是那些明確標示了…

由pandas.loc引發的未知錯誤AttributeError: ‘str‘ object has no attribute ‘isna‘

由于data.loc[value]和 data[data.keyvalue] 這兩者之間有一定的差異&#xff0c;第一種方式返回的可能是series&#xff0c;第二種方式返回的是dataframe&#xff0c;所以在做復雜條件篩選的的時候&#xff0c;可能會爆str相關的錯誤。 例如&#xff1a; account_instal[(ac…

嵌入式開發按怎樣的路線學習較好?

嵌入式開發按怎樣的路線學習較好&#xff1f; 在開始前我有一些資料&#xff0c;是我根據自己從業十年經驗&#xff0c;熬夜搞了幾個通宵&#xff0c;精心整理了一份「嵌入式從專業入門到高級教程工具包」&#xff0c;點個關注&#xff0c;全部無償共享給大家&#xff01;&…

mysql的行鎖具體是怎么工作的

mysql行級鎖是怎么工作的&#xff1f; 加鎖的對象是索引&#xff0c;加鎖的基本單位是 next-key lock。在能使用記錄鎖或者間隙鎖就能避免幻讀現象的場景下&#xff0c; next-key lock 就會退化成記錄鎖或間隙鎖。 鎖的范圍&#xff0c;總結一下就是&#xff0c;對于唯一索引&a…

張馳咨詢:掌握流程改進的關鍵,深入了解六西格瑪綠帶培訓

尊敬的讀者&#xff0c;當您尋求提升個人能力&#xff0c;加強企業流程管理時&#xff0c;六西格瑪綠帶培訓無疑是您的不二選擇。本文將帶您深入了解六西格瑪綠帶培訓的核心內容、必備工具和實際案例&#xff0c;以助您在職業生涯中一帆風順。 六西格瑪綠帶培訓主要針對中層管…

C++- 格式化輸出

1.常規–格式化輸出 &#xff05;d //整型輸出 &#xff05;ld //長整型輸出 &#xff05;o //以八進制數形式輸出整數 &#xff05;x //以十六進制數形式輸出整數&#xff0c;或輸出字符串的地址 &#xff05;u //以十進制數輸出unsigned型數據(無符號數)注意&…

element 點擊button彈出圖片 運用自帶隱藏的圖片查看器el-image-viewer瀏覽圖片

最近在開發一個圖片預覽效果&#xff0c;由于位置有限&#xff0c;沒有原始的縮略圖。 看了下elementUI的文檔&#xff0c;基本都是需要有縮略圖的情況下&#xff0c;才能有放大的圖。 所以網上找了下有個不錯的方案&#xff0c;其實也是elementUI自帶的功能&#xff0c;只是AP…

論文查重怎么找到需要更改的【詳細說明】

大家好&#xff0c;今天來聊聊論文查重怎么找到需要更改的&#xff0c;希望能給大家提供一點參考。 以下是針對論文重復率高的情況&#xff0c;提供一些修改建議和技巧&#xff1a; 論文查重怎么找到需要更改的 論文查重是保證學術誠信和提高論文質量的重要環節小發貓偽原創。…

班級管理的重要性

班級管理&#xff0c;就像是一座橋&#xff0c;連接著學生和老師&#xff0c;它的重要性不言而喻。 營造良好的學習氛圍 班級管理不僅僅是維護秩序&#xff0c;更是營造一個積極向上的學習氛圍。一個好的班級管理&#xff0c;能讓學生更加專注于學習&#xff0c;提高學習效率。…

Linux上的MAC地址欺騙

Linux上的MAC地址欺騙 1、查看mac地址法1&#xff1a;ifconfig法2&#xff1a;ip link show 2、臨時性改變 MAC 地址法1&#xff1a;使用iproute2工具包法2&#xff1a;使用macchanger工具 3、永久性改變 MAC 地址3.1 在 Fedora、RHEL下實踐3.2 在 Debian、Ubuntu、Linux Mint下…

人工智能革命近在咫尺:利用數據實現社會影響、增強決策力和新機遇

人工智能&#xff08;AI&#xff09;是指由計算機系統或機器執行的智能行為&#xff0c;如學習、推理和解決問題。人工智能不再是科幻小說中的事物&#xff0c;而是已經成為我們日常生活中不可或缺的一部分。從語音助手到自動駕駛汽車&#xff0c;從人臉識別到機器翻譯&#xf…

數據結構之----原碼、反碼、補碼

數據結構之----原碼、反碼、補碼 什么是原碼&#xff1f; 原碼&#xff1a;我們將數字的二進制表示的最高位視為符號位&#xff0c;其中 0 表示正數&#xff0c;1 表示負數&#xff0c;其余位表示數字 的值。 什么是反碼&#xff1f; 反碼&#xff1a;正數的反碼與其原碼相…

網絡攻擊(二)--情報搜集階段

4.1. 概述 在情報收集階段&#xff0c;你需要采用各種可能的方法來收集將要攻擊的客戶組織的所有信息&#xff0c;包括使用社交網絡、Google Hacking技術、目標系統踩點等等。 而作為滲透測試者&#xff0c;你最為重要的一項技能就是對目標系統的探查能力&#xff0c;包括獲知…

文生圖:AE/VAE/VQVAE/VQGAN/DALLE模型

文生圖模型演進&#xff1a;AE、VAE、VQ-VAE、VQ-GAN、DALL-E 等 8 模型本文中我們回顧了 AE、VAE、VQ-VAE、VQ-VAE-2 以及 VQ-GAN、DALL-E、DALL-E mini 和 CLIP-VQ-GAN 等 8 中模型&#xff0c;以介紹文生圖模型的演進。https://mp.weixin.qq.com/s/iFrCEpAJ3WMhB-01lZ_qIA 1…

pta模擬題(7-38 完全二叉樹的層序遍歷)

一個二叉樹&#xff0c;如果每一個層的結點數都達到最大值&#xff0c;則這個二叉樹就是完美二叉樹。對于深度為 D 的&#xff0c;有 N 個結點的二叉樹&#xff0c;若其結點對應于相同深度完美二叉樹的層序遍歷的前 N 個結點&#xff0c;這樣的樹就是完全二叉樹。 給定一棵完全…

GaussDB數據庫語法及gsql入門

一、GaussDB數據庫語法入門 之前我們講了如何連接數據庫實例&#xff0c;那連接數據庫后如何使用數據庫呢&#xff1f;那么我們今天就帶大家了解一下GaussDB&#xff0c;以下簡稱GaussDB的基本語法。 關于如何連接數據庫&#xff0c;請戳這里。 學習本節課程之后&#xff0c…

【開題報告】基于SpringBoot的消防知識科普平臺的設計與實現

1.選題背景 消防知識科普平臺的設計與實現是為了提高公眾對于消防安全的認知和應對能力&#xff0c;促進社會消防文化的普及和發展。在中國&#xff0c;火災事故時有發生&#xff0c;造成了重大人員傷亡和財產損失。因此&#xff0c;建立一個基于Spring Boot的消防知識科普平臺…

docker---網絡

docker的網絡模式&#xff1a; 1、橋接模式&#xff1a;創建docker時不需要指定網絡類型&#xff0c;默認模式。 2、host模式: 容器將不會虛擬出自己的網卡&#xff0c;也沒有自己的ip地址&#xff0c;全部使用宿主機的ip和端口。 3、container模式&#xff1a;容器和容器之間…

第五屆計算機能力挑戰賽國賽C語言組題解(專科組)

前言&#xff1a; ??前兩天計算機能力挑戰賽國賽結束了&#xff0c;拿著題做了一遍&#xff0c;發現難度真的不大&#xff0c;比省賽簡單多了&#xff0c;只是有時候可能有的同學拿著題&#xff0c;沒認真仔細去讀&#xff0c;或者說緊張了導致自己發揮不好吧。以下是個人的題…