什麼是跨域
CORS全稱:Cross-Origin Resource Sharing
在前後台分離的應用開發中,跨域是經常需要處理的情境。指的是訪問不同網域名稱的資源,對於靜態資源的訪問,比如CSS、GIF、Form請求,不存在跨域問題,一般說跨域問題,就是指的JavaScript的跨域問題以及Cookie的跨域使用問題(是使用,不是讀取內容)。
跨域問題的根本原因是瀏覽器的安全限制,預設禁止跨域的動態資源請求。
參考文章:
http://www.cnblogs.com/rainman/archive/2011/02/20/1959325.html
AJAX POST&跨域 解決方案 - CORS
https://www.zhihu.com/question/26379635
Java伺服器端跨域解決
一個Java應用,為了支援跨域,允許其他網域名稱的JavaScript指令碼訪問本應用的資源,通常是在web.xml裡面配置一個跨域處理Filter。
<!-- 允許跨域 --><filter> <filter-name>crossDomainFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param></filter><filter-mapping> <filter-name>crossDomainFilter</filter-name> <url-pattern>/*</url-pattern><!-- 配置允許跨域訪問的的url-pattern --></filter-mapping>
跨域Filter的一般寫法如下:
@Component("crossDomainFilter")public class crossDomainFilter implements Filter { private static Logger errorLogger = LoggerFactory.getLogger(LogConstants.ERROR); @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { try { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; // 跨域 String origin = httpRequest.getHeader("Origin"); if (origin == null) { httpResponse.addHeader("Access-Control-Allow-Origin", "*"); } else { httpResponse.addHeader("Access-Control-Allow-Origin", origin); } httpResponse.addHeader("Access-Control-Allow-Headers", "Origin, x-requested-with, Content-Type, Accept,X-Cookie"); httpResponse.addHeader("Access-Control-Allow-Credentials", "true"); httpResponse.addHeader("Access-Control-Allow-Methods", "GET,POST,PUT,OPTIONS,DELETE"); if ( httpRequest.getMethod().equals("OPTIONS") ) { httpResponse.setStatus(HttpServletResponse.SC_OK); return; } chain.doFilter(request, response); } catch (Exception e) { errorLogger.error("Exception in crossDomainFilter.doFilter", e); throw e; } } @Override public void destroy() { }}
跨域解決辦法原理
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
1、跨域時,瀏覽器會先發一次OPTIONS請求:OPTIONS 方法在跨域請求(CORS)中的應用
2、Access-Control-Allow-Origin與跨域:http://www.tuicool.com/articles/7FVnMz
3、Access-Control-Allow-Credentials於Cookie:http://zawa.iteye.com/blog/1868108 ,這在SSO中有用,調用方(a.com)把本應用(b.com)的cookie帶給SSO,達到了登入認證的目的。
一個Cookie帶不上的案例
一個真實項目中,跨域時Cookie沒有帶上,其中後端有:servletResponse.setHeader("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE");
前端也有:withCredentials: true 的配置。
解決問題的文章:https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
由於瀏覽器發送預檢請求時,即OPTIONS,發現後端Access-Control-Allow-Methods沒有OPTIONS,則後續的跨域請求就終止了,也就不會有後續的帶Cookie的事情了。
前後台分離系統跨域時兩種解決辦法
情境:前端是a.com;後端是b.com,則解決跨域有如下兩種情境:
1、配置好允許跨域相關配置,a.com請求b.com時,每次都通過跨域的配置,把cookie或者自訂Http頭內容傳給b.com,b.com拿到相關資料後進行身分識別驗證;這種辦法對於使用者身份的cookie資訊,實際是種在a.com下面的;這種方式需要前端處理登入,寫Cookie等操作;
2、置好允許跨域相關配置,a.com請求b.com時,發現沒有許可權,則請求b.com的一個登入中轉頁面,b.com登入後,把使用者身份資訊種在b.com的cookie下面;這種方式,前端是純展示層,不需要處理登入,寫Cookie等操作。
總結
吃透了瀏覽器行為,和Http協議,就能對跨域有比較深刻的瞭解了。貌似這和前端更相關一些。實際的工作中,也是感覺前端對這些理解的更透徹,而後端的RD們更注重的是效能,比較不Care這些技術。