1、前言
最近在項目中,調用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跨越問題的起因與詳細解決辦法。
2、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
3、解決辦法
在查閱大量資源,並了解過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() { …… } }
PS:本文轉載自:https://blog.csdn.net/xcbeyond/article/details/84453832