[轉]跨域問題(CORS / Access-Control-Allow-Origin)

原文連接:https://blog.csdn.net/xcbeyond/article/details/84453832前端

一、前言

      最近在項目中,調用Eureka REST接口時,出現了CORS跨越問題(Cross-origin resource sharing),在此與你們進行分享,避免多走些彎路。

      項目前端(http://localhost:9000)經過Ajax方式調用Eureka REST 接口(http://localhost:8761/eureka/apps)時,卻沒有任何反應,則經過F12查看日誌發現出現「Access-Control-Allow-Origin「類 異常,詳細以下:

…… http://localhost:8761/eureka/apps. Origin http://localhost:9000 is not allowed by Access-Control-Allow-Origin……

經過google,發現是因爲CORS跨越問題形成的,解決辦法無非有兩種方式:響應頭添加參數和添加過濾器,下面就詳細說說CORS跨越問題的原由與詳細解決辦法。
二、CORS

     CORS,常被你們稱之爲跨越問題,準確的叫法是跨域資源共享(CORS,Cross-origin resource sharing),是W3C標準,是一種機制,它使用額外的HTTP頭來告訴瀏覽器 讓運行在一個 origin (domain) 上的Web應用被准許訪問來自不一樣源服務器上的指定的資源。當一個資源從與該資源自己所在的服務器不一樣的域或端口請求一個資源時,資源會發起一個跨域 HTTP 請求。

     http://localhost:9000請求http://localhost:8761/eureka/apps就是違背了上述原則,即:請求服務器不一樣端口的另外一個資源,出於安全緣由,瀏覽器限制發起的跨源HTTP請求,則會出現本文開頭提到的現象及異常。

     例如,XMLHttpRequest和Fetch API遵循同源策略, 這意味着使用這些API的Web應用程序只能從加載應用程序的同一個域請求HTTP資源,除非使用CORS頭。

      跨域資源共享( CORS )機制容許 Web 應用服務器進行跨域訪問控制,從而使跨域數據傳輸得以安全進行。瀏覽器支持在 API 容器中(例如 XMLHttpRequest 或 Fetch )使用 CORS,以下降跨域 HTTP 請求所帶來的風險。
什麼狀況下存在跨域問題

    本文提到的由 XMLHttpRequest 或 Fetch 發起的跨域 HTTP 請求。
    Web 字體 (CSS 中經過 @font-face 使用跨域字體資源),,所以,網站就能夠發佈 TrueType 字體資源,並只容許已受權網站進行跨站調用。
    WebGL 貼圖。
    使用 drawImage 將 Images/video 畫面繪製到 canvas
    樣式表(使用 CSSOM)。

 
面對CORS的限制,將如何解決呢

     世間萬物完事,有因必有果,有果必有因。固然CORS的限制,官方也是給出瞭解決辦法的。

     CORS標準新增了一組 HTTP 頭字段(Access-Control-Allow-Origin),容許服務器聲明哪些源經過瀏覽器有權限訪問哪些資源。另外,規範要求,對那些可能對服務器數據產生反作用的 HTTP 請求方法(特別是 GET之外的 HTTP 請求,或者搭配某些 MIME 類型的 POST請求),瀏覽器必須首先使用 OPTIONS 方法發起一個預檢請求(preflight request),從而獲知服務端是否容許該跨域請求。服務器確認容許以後,才發起實際的 HTTP 請求。在預檢請求的返回中,服務器端也能夠通知客戶端,是否須要攜帶身份憑證(包括Cookies 和 HTTP 認證相關數據)。

      CORS請求失敗會產生錯誤,可是爲了安全,在JavaScript代碼層面是沒法獲知到底具體是哪裏出了問題。你只能查看瀏覽器的控制檯以得知具體是哪裏出現了錯誤。

若是有興趣瞭解該機制剖析的能夠參考https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
三、解決辦法

      在查閱大量資源,並瞭解過CORS機制後,解決辦法實質一定會圍繞Access-Control-Allow-Origin頭。

解決辦法以下:
添加響應頭

     在被請求資源中添加響應頭信息"Access-Control-Allow-Origin:*
過濾器

    在本項目中添加以下過濾器:

    /**
     * 解決跨域問題
     */
    public class AccessControlAllowOriginFilter implements Filter {
     
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
            HttpServletResponse response = (HttpServletResponse) res;
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
            response.setHeader("Access-Control-Allow-Credentials", "true");
     
         chain.doFilter(req, response);
       }
     
       public void init(FilterConfig filterConfig) {
     
       }
     
       public void destroy() {
     
       }
     
    }

註解方式

      在Spring Boot中擁有大量的註解,針對跨域問題,也提供了對應的註解@CrossOrigin,使用方法以下:

    import java.util.HashMap;
     
    import org.springframework.web.bind.annotation.CrossOrigin;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
     
    /**
     * @author xcbeyond
     */
    @RestController
    @RequestMapping(value = "/api", method = RequestMethod.POST)
    public class DemoController {
            
        @CrossOrigin(origins = "*")
        @RequestMapping(value = "/get")
        public String get() {
            ……
        }
    }

 我的比較推薦使用上述的三種方式之一,其餘方式請本身百度、谷歌吧


java

相關文章
相關標籤/搜索