亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

關(guān)于后端如何解決跨域的問題說明

 更新時(shí)間:2022年08月30日 11:22:57   作者:CrazySnail_x  
這篇文章主要介紹了關(guān)于后端如何解決跨域的問題說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

對(duì)于跨域,相信同學(xué)們都有所了解。前端的跨域的若干種方式,大家也都知道,什么 JSONP,iframe+domain 等等。但是我們今天的主題,不是前端跨域,而是后端跨域。

一旦提及到跨域,就會(huì)想到同源策略,那我們就先來回顧跨域和同源策略。

什么是跨域請(qǐng)求

首先,我們要了解什么是跨域請(qǐng)求。簡單來說,當(dāng)一臺(tái)服務(wù)器資源從另一臺(tái)服務(wù)器(不同 的域名或者端口)請(qǐng)求一個(gè)資源或者接口,就會(huì)發(fā)起一個(gè)跨域 HTTP 請(qǐng)求。

舉個(gè)簡單的例子:

從http://aaa.com/index.html,發(fā)送一個(gè) Ajax 請(qǐng)求,請(qǐng)求地址是 http://bbb.com/下面的一個(gè)接口,這就是發(fā)起了一個(gè)跨域請(qǐng)求。在不做任何處理的情況下,這個(gè)跨域請(qǐng)求是無法被成功請(qǐng)求的,因?yàn)闉g覽器基于同源策略 會(huì)對(duì)跨域請(qǐng)求做一定的限制。那什么又是同源策略呢?

什么是同源策略

首先大家要知道同源策略發(fā)生的場(chǎng)景——瀏覽器中,什么意思呢?如果不是瀏覽器的話, 就不會(huì)受到同源策略的影響。也就是說,兩個(gè)服務(wù)器直接進(jìn)行跨域請(qǐng)求是可以進(jìn)行數(shù)據(jù)請(qǐng)求的。這也就為我們接下來的后端跨域埋下一下小伏筆。 同源策略的目的是什么呢?同源策略限制了從同一個(gè)源加載的文檔或者腳本如何與來自另 一個(gè)源的資源進(jìn)行交互。這是一個(gè)用于隔離潛在惡意文件的重要安全機(jī)制。

同源策略限制內(nèi)容有

  • Cookie、LocalStorage、IndexedDB 等存儲(chǔ)性內(nèi)容
  • DOM 節(jié)點(diǎn)
  • AJAX 請(qǐng)求不能發(fā)送

那什么又是同源?

大家都知道,一個(gè)域名請(qǐng)求地址的組成是:協(xié)議+域名+端口號(hào)+請(qǐng)求資源地址 , 當(dāng)協(xié)議、域名、端口號(hào)中任意一個(gè)不相同時(shí) , 都算作不同源(必須是域名完全相同,比如說 a.example.com 和 b.example.com 這兩個(gè)域名。

雖然它們的頂級(jí)域名和二級(jí)域名(均為 example.com)都相同,但是三級(jí)域名(a 和 b)不相同,所以也不能算作域名相同)。

如果不同時(shí)滿足這上面三個(gè)條件,那就不符合瀏覽器的同源策略。 需要注意的是,不是所有的交互都會(huì)被同源策略攔截下來,下面兩種交互就不會(huì)觸發(fā)同源策略: 

跨域?qū)懖僮鳎–ross-origin writes)

  • 例如超鏈接、重定向以及表單的提交操 作,特定少數(shù)的 HTTP 請(qǐng)求需要添加預(yù)檢請(qǐng)求(preflight)

跨域資源嵌入(Cross-origin embedding)

  • <script> 標(biāo)簽嵌入的跨域腳本; o <link> 標(biāo)簽嵌入的 CSS 文件; o <img> 標(biāo)簽嵌入圖片;
  • <video> 和 <audio> 標(biāo)簽嵌入多媒體資源; o <object>, <embed>, <applet> 的插件;
  • @font-face 引入的字體,一些瀏覽器允許跨域字體(cross-origin fonts),一些需要同源字體(same-origin fonts);
  • <frame> 和 <iframe> 載入的任何資源,站點(diǎn)可以使用 X-FrameOptions 消息頭來組織這種形式的跨域交互。

這里你或許有個(gè)疑問:請(qǐng)求跨域了,那么請(qǐng)求到底發(fā)出去沒有?

跨域并不是請(qǐng)求發(fā)不出去,請(qǐng)求能發(fā)出去,服務(wù)端能收到請(qǐng)求并正常返回結(jié)果,只是結(jié)果被瀏覽器攔截了。

你可能會(huì)疑問明明通過表單的方式可以發(fā)起跨域請(qǐng)求,為什么 Ajax 就不會(huì)?因?yàn)闅w根結(jié)底,跨域是為了阻止用戶讀取到另一個(gè)域名下的內(nèi)容,Ajax 可以獲取響應(yīng),瀏覽器認(rèn)為這不安全,所以攔截了響應(yīng)。但是表單并不會(huì)獲取新的內(nèi)容,所以可以發(fā)起跨域請(qǐng)求。

同時(shí)也說明了跨域并不能完全阻止 CSRF,因?yàn)檎?qǐng)求畢竟是發(fā)出去了。

跨域解決方案

跨域就是通過某些手段來繞過同源策略限制,實(shí)現(xiàn)不同服務(wù)器之間通信的效果。方法有很多 ,大致分為兩類:

  • 服務(wù)端進(jìn)行設(shè)置默認(rèn)允許某些域名跨域訪問
  • 從客戶端入手想辦法繞開同源安全策略

常見的解決方案有:

1.jsonp

利用 <script> 標(biāo)簽沒有跨域限制的漏洞,網(wǎng)頁可以得到從其他來源動(dòng)態(tài)產(chǎn)生的 JSON 數(shù)據(jù)。JSONP請(qǐng)求一定需要對(duì)方的服務(wù)器做支持才可以。

JSONP和AJAX相同,都是客戶端向服務(wù)器端發(fā)送請(qǐng)求,從服務(wù)器端獲取數(shù)據(jù)的方式。但AJAX屬于同源策略,JSONP屬于非同源策略(跨域請(qǐng)求)

JSONP優(yōu)點(diǎn)是簡單兼容性好,可用于解決主流瀏覽器的跨域數(shù)據(jù)訪問的問題。缺點(diǎn)是僅支持get方法具有局限性,不安全可能會(huì)遭受XSS攻擊。

2.cors

CORS(Cross-origin resource sharing),跨域資源共享。CORS 其實(shí)是瀏覽器制定的一個(gè)規(guī)范,瀏覽器會(huì)自動(dòng)進(jìn)行 CORS 通信,它的實(shí)現(xiàn)則主要在服務(wù)端,它通過一些 HTTP Header 來限制可以訪問的域,例如頁面 A 需要訪問 B 服務(wù)器上的數(shù)據(jù),如果 B 服務(wù)器 上聲明了允許 A 的域名訪問,那么從 A 到 B 的跨域請(qǐng)求就可以完成。對(duì)于那些會(huì)對(duì)服務(wù)器數(shù)據(jù)產(chǎn)生副作用的 HTTP 請(qǐng)求,瀏覽器會(huì)使用 OPTIONS 方法發(fā)起 一個(gè)預(yù)檢請(qǐng)求(preflight request),從而可以獲知服務(wù)器端是否允許該跨域請(qǐng)求,服 務(wù)器端確認(rèn)允許后,才會(huì)發(fā)起實(shí)際的請(qǐng)求。在預(yù)檢請(qǐng)求的返回中,服務(wù)器端也可以告知客 戶端是否需要身份認(rèn)證信息。我們只需要設(shè)置響應(yīng)頭,即可進(jìn)行跨域請(qǐng)求。

雖然設(shè)置 CORS 和前端沒什么關(guān)系,但是通過這種方式解決跨域問題的話,會(huì)在發(fā)送請(qǐng)求時(shí)出現(xiàn)兩種情況,分別為簡單請(qǐng)求和復(fù)雜請(qǐng)求。

簡單請(qǐng)求:

只要同時(shí)滿足以下兩大條件,就屬于簡單請(qǐng)求:

1)使用GET、HEAD、POST方法之一;

2)Content-Type 的值僅限于:text/plain、multipart/form-data、application/x-www-form-urlencoded,請(qǐng)求中的任意 XMLHttpRequestUpload 對(duì)象均沒有注冊(cè)任何事件監(jiān)聽器; XMLHttpRequestUpload 對(duì)象可以使用 XMLHttpRequest.upload 屬性訪問;

復(fù)雜請(qǐng)求:

不符合以上條件的請(qǐng)求就肯定是復(fù)雜請(qǐng)求了。 復(fù)雜請(qǐng)求的CORS請(qǐng)求,會(huì)在正式通信之前,增加一次HTTP查詢請(qǐng)求,稱為"預(yù)檢"請(qǐng)求,該請(qǐng)求是 option 方法的,通過該請(qǐng)求來知道服務(wù)端是否允許跨域請(qǐng)求。

我們用PUT向后臺(tái)請(qǐng)求時(shí),屬于復(fù)雜請(qǐng)求,后臺(tái)需被請(qǐng)求的Servlet中添加Header設(shè)置,Access-Control-Allow-Origin這個(gè)Header在W3C標(biāo)準(zhǔn)里用來檢查該跨域請(qǐng)求是否可以被通過,如果值為*則表明當(dāng)前頁面可以跨域訪問。默認(rèn)的情況下是不允許的。

一般我們可以寫一個(gè)過濾器: 

@WebFilter(filterName = "corsFilter", urlPatterns = "/*",
        initParams = {@WebInitParam(name = "allowOrigin", value = "*"),
                @WebInitParam(name = "allowMethods", value = "GET,POST,PUT,DELETE,OPTIONS"),
                @WebInitParam(name = "allowCredentials", value = "true"),
                @WebInitParam(name = "allowHeaders", value = "Content-Type,X-Token")})
public class CorsFilter implements Filter {
 
    private String allowOrigin;
    private String allowMethods;
    private String allowCredentials;
    private String allowHeaders;
    private String exposeHeaders;
 
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        allowOrigin = filterConfig.getInitParameter("allowOrigin");
        allowMethods = filterConfig.getInitParameter("allowMethods");
        allowCredentials = filterConfig.getInitParameter("allowCredentials");
        allowHeaders = filterConfig.getInitParameter("allowHeaders");
        exposeHeaders = filterConfig.getInitParameter("exposeHeaders");
    }
 
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        if (!StringUtils.isEmpty(allowOrigin)) {
            if(allowOrigin.equals("*")){
                // 設(shè)置哪個(gè)源可以訪問
                response.setHeader("Access-Control-Allow-Origin", allowOrigin);
            }else{
                List<String> allowOriginList = Arrays.asList(allowOrigin.split(","));
                if (allowOriginList != null && allowOriginList.size() > 0) {
                    String currentOrigin = request.getHeader("Origin");
                    if (allowOriginList.contains(currentOrigin)) {
                        response.setHeader("Access-Control-Allow-Origin", currentOrigin);
                    }
                }
            }
        }
        if (!StringUtils.isEmpty(allowMethods)) {
            //設(shè)置哪個(gè)方法可以訪問
            response.setHeader("Access-Control-Allow-Methods", allowMethods);
        }
        if (!StringUtils.isEmpty(allowCredentials)) {
            // 允許攜帶cookie
            response.setHeader("Access-Control-Allow-Credentials", allowCredentials);
        }
        if (!StringUtils.isEmpty(allowHeaders)) {
            // 允許攜帶哪個(gè)頭
            response.setHeader("Access-Control-Allow-Headers", allowHeaders);
        }
        if (!StringUtils.isEmpty(exposeHeaders)) {
            // 允許攜帶哪個(gè)頭
            response.setHeader("Access-Control-Expose-Headers", exposeHeaders);
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }
 
    @Override
    public void destroy() {
 
    }
}

大功告成,現(xiàn)在前端就可以跨域獲取后臺(tái)的數(shù)據(jù)了,正如我們上面所說的,后端是實(shí)現(xiàn) CORS 通信的關(guān)鍵。 

如果你的SpringBoot版本在2.0以上,以下代碼配置即可完美解決你的前后端跨域請(qǐng)求問題:

@Configuration
public class CorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration corsConfiguration = new CorsConfiguration();
        /*是否允許請(qǐng)求帶有驗(yàn)證信息*/
        corsConfiguration.setAllowCredentials(true);
        /*允許訪問的客戶端域名*/
        corsConfiguration.addAllowedOrigin("*");
        /*允許服務(wù)端訪問的客戶端請(qǐng)求頭*/
        corsConfiguration.addAllowedHeader("*");
        /*允許訪問的方法名,GET POST等*/
        corsConfiguration.addAllowedMethod("*");
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(urlBasedCorsConfigurationSource);
    }
}

或者使用WebMvcConfigurationSupport,實(shí)現(xiàn)方式有很多,感興趣的可以自行研究。

3.@CrossOrigin注解

這個(gè)方法僅對(duì)Java有用。springboot中,在Controller類上添加一個(gè) @CrossOrigin(origins ="*") 注解就可以實(shí)現(xiàn)對(duì)當(dāng)前controller 的跨域訪問了,當(dāng)然這個(gè)標(biāo)簽也可以加到方法上,或者直接加到入口類上對(duì)所有接口進(jìn)行跨域處理,注意這個(gè)注解只在JDK1.8版本以上才起作用。

4.使用SpringCloud網(wǎng)關(guān)

服務(wù)網(wǎng)關(guān)(zuul)又稱路由中心,用來統(tǒng)一訪問所有api接口,維護(hù)服務(wù)。

Spring Cloud Zuul通過與Spring Cloud Eureka的整合,實(shí)現(xiàn)了對(duì)服務(wù)實(shí)例的自動(dòng)化維護(hù),所以在使用服務(wù)路由配置的時(shí)候,我們不需要向傳統(tǒng)路由配置方式那樣去指定具體的服務(wù)實(shí)例地址,只需要通過Ant模式配置文件參數(shù)即可

5.Node中間件代理(兩次跨域)

實(shí)現(xiàn)原理:同源策略是瀏覽器需要遵循的標(biāo)準(zhǔn),而如果是服務(wù)器向服務(wù)器請(qǐng)求就無需遵循同源策略。這樣的話,我們可以讓服務(wù)器替我們發(fā)送一個(gè)請(qǐng)求,請(qǐng)求其他服務(wù)器下面的數(shù)據(jù)。然后我們的頁面訪問當(dāng)前服務(wù)器下的接口就沒有跨域問題了。 

代理服務(wù)器,需要做以下幾個(gè)步驟:

  • 接受客戶端請(qǐng)求 。
  • 將請(qǐng)求 轉(zhuǎn)發(fā)給服務(wù)器。
  • 拿到服務(wù)器 響應(yīng) 數(shù)據(jù)。
  • 將 響應(yīng) 轉(zhuǎn)發(fā)給客戶端。

6.nginx反向代理

實(shí)現(xiàn)原理類似于Node中間件代理,需要你搭建一個(gè)中轉(zhuǎn)nginx服務(wù)器,用于轉(zhuǎn)發(fā)請(qǐng)求。

使用nginx反向代理實(shí)現(xiàn)跨域,是最簡單的跨域方式。只需要修改nginx的配置即可解決跨域問題,支持所有瀏覽器,支持session,不需要修改任何代碼,并且不會(huì)影響服務(wù)器性能。

實(shí)現(xiàn)思路:通過nginx配置一個(gè)代理服務(wù)器做跳板機(jī),反向代理訪問domain2接口,并且可以順便修改cookie中domain信息,方便當(dāng)前域cookie寫入,實(shí)現(xiàn)跨域登錄。

將nginx目錄下的nginx.conf修改如下:

// proxy服務(wù)器
server {
    listen       81;
    server_name  www.domain1.com;
    location / {
        proxy_pass   http://www.domain2.com:8080;  #反向代理
        proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
        index  index.html index.htm;
 
        # 當(dāng)用webpack-dev-server等中間件代理接口訪問nignx時(shí),此時(shí)無瀏覽器參與,故沒有同源限制,下面的跨域配置可不啟用
        add_header Access-Control-Allow-Origin http://www.domain1.com;  #當(dāng)前端只跨域不帶cookie時(shí),可為*
        add_header Access-Control-Allow-Credentials true;
        add_header Access-Control-Allow-Methods GET, POST, OPTIONS;
        add_header Access-Control-Allow-Headers *;
    }
}

這樣我們的前端代理只要訪問 http:www.domain1.com:81/*就可以了。

總結(jié)

  • CORS支持所有類型的HTTP請(qǐng)求,是跨域HTTP請(qǐng)求的根本解決方案
  • JSONP只支持GET請(qǐng)求,JSONP的優(yōu)勢(shì)在于支持老式瀏覽器,以及可以向不支持CORS的網(wǎng)站請(qǐng)求數(shù)據(jù)。
  • 不管是Node中間件代理還是nginx反向代理,主要是通過同源策略對(duì)服務(wù)器不加限制。
  • 日常工作中,用得比較多的跨域方案是cors和nginx反向代理

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。 

相關(guān)文章

  • Java如何利用POI讀取Excel行數(shù)

    Java如何利用POI讀取Excel行數(shù)

    這篇文章主要介紹了java如何利用POI讀取Excel行數(shù),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • 詳解SpringBoot2.0的@Cacheable(Redis)緩存失效時(shí)間解決方案

    詳解SpringBoot2.0的@Cacheable(Redis)緩存失效時(shí)間解決方案

    這篇文章主要介紹了詳解SpringBoot2.0的@Cacheable(Redis)緩存失效時(shí)間解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Java List雙擊事件實(shí)現(xiàn)方法

    Java List雙擊事件實(shí)現(xiàn)方法

    這篇文章主要介紹了Java List雙擊事件實(shí)現(xiàn)方法,需要的朋友可以參考下
    2014-09-09
  • Scala入門教程詳解

    Scala入門教程詳解

    這篇文章主要介紹了Scala入門教程詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • java判斷http地址是否連通(示例代碼)

    java判斷http地址是否連通(示例代碼)

    這篇文章通過實(shí)例代碼給大家介紹了java判斷http地址是否連通,文末給大家補(bǔ)充知識(shí)點(diǎn)url.openconnection() 設(shè)置超時(shí)時(shí)間的方法,感興趣的朋友跟隨小編一起看看吧
    2021-12-12
  • 如何解決java.lang.ClassNotFoundException: com.mysql.jdbc.Driver問題

    如何解決java.lang.ClassNotFoundException: com.mysql.jdbc.Dr

    這篇文章主要介紹了如何解決java.lang.ClassNotFoundException: com.mysql.jdbc.Driver問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Java詳細(xì)分析String類與StringBuffer和StringBuilder的使用方法

    Java詳細(xì)分析String類與StringBuffer和StringBuilder的使用方法

    當(dāng)對(duì)字符串進(jìn)行修改的時(shí)候,需要使用 StringBuffer 和 StringBuilder類,和String類不同的是,StringBuffer和 StringBuilder類的對(duì)象能夠被多次的修改,并且不產(chǎn)生新的未使用對(duì)象
    2022-04-04
  • Java對(duì)數(shù)組實(shí)現(xiàn)選擇排序算法的實(shí)例詳解

    Java對(duì)數(shù)組實(shí)現(xiàn)選擇排序算法的實(shí)例詳解

    這篇文章主要介紹了Java對(duì)數(shù)組實(shí)現(xiàn)選擇排序算法的實(shí)例,選擇排序的比較次數(shù)為 O(N^2)而交換數(shù)為O(N),需要的朋友可以參考下
    2016-04-04
  • springboot+kafka中@KafkaListener動(dòng)態(tài)指定多個(gè)topic問題

    springboot+kafka中@KafkaListener動(dòng)態(tài)指定多個(gè)topic問題

    這篇文章主要介紹了springboot+kafka中@KafkaListener動(dòng)態(tài)指定多個(gè)topic問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • mybatis-plus配置日志兩種實(shí)現(xiàn)方式

    mybatis-plus配置日志兩種實(shí)現(xiàn)方式

    這篇文章主要給大家介紹了關(guān)于mybatis-plus配置日志兩種實(shí)現(xiàn)方式的相關(guān)資料,Mybatis-plus集成了日志框架,可以將程序運(yùn)行時(shí)產(chǎn)生的日志進(jìn)行記錄,方便開發(fā)人員進(jìn)行問題排查,需要的朋友可以參考下
    2023-09-09

最新評(píng)論