摘要:大家都知道可以通過實(shí)現(xiàn)跨域。第一種方式在服務(wù)下添加一個(gè)實(shí)現(xiàn)跨域,實(shí)現(xiàn)起來方便。前端服務(wù)和后端服務(wù)在同一臺(tái)服務(wù)器上,服務(wù)調(diào)用服務(wù)時(shí),服務(wù)通過負(fù)載均衡進(jìn)入服務(wù)時(shí)時(shí),服務(wù)的請求跨域成功,時(shí),服務(wù)的請求跨域失敗。
大家都知道spring boot 可以通過@CrossOrigin實(shí)現(xiàn)跨域。但是在spring cloud 里,如果要粒度那么細(xì)的去控制跨域,這個(gè)就太繁瑣了,所以一般來說,會(huì)在路由zuul里實(shí)現(xiàn)。
第一種方式:corsFilter在zuul服務(wù)下添加一個(gè)corsFilter實(shí)現(xiàn)跨域,實(shí)現(xiàn)起來方便。代碼如下
@Configuration public class GateWayCorsConfig { @Bean public FilterRegistrationBean corsFilter() { final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); final CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin("*"); config.addAllowedHeader("*"); config.addAllowedMethod("*"); //這個(gè)請求頭在https中會(huì)出現(xiàn),但是有點(diǎn)問題,下面我會(huì)說 //config.addExposedHeader("X-forwared-port, X-forwarded-host"); source.registerCorsConfiguration("/**", config); FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source)); bean.setOrder(Ordered.HIGHEST_PRECEDENCE); return bean; } }
經(jīng)過測試,這樣的配置在http的情況下跨域是OK的,但是當(dāng)我的環(huán)境切換的https的情況下就發(fā)生了奇怪的問題。說明一下我遇到的問題。
前端 服務(wù)A 和 后端服務(wù)B 在同一臺(tái)服務(wù)器上,服務(wù)A 調(diào)用 服務(wù)B 時(shí),服務(wù)A通過負(fù)載均衡進(jìn)入服務(wù)B時(shí):
http時(shí),服務(wù)A的請求跨域成功,https時(shí),服務(wù)A的請求跨域失敗。
也就是端口為443的時(shí)候,會(huì)被認(rèn)為跨域失?。?!
我一開始對比了請求頭,以為是少了ExposedHeader的"X-forwared-port, X-forwarded-host",但是添加后,還是失敗。因?yàn)榧敝暇€,所以我沒有去深入測試到底什么原因引起的https請求跨域失敗。(所以如果大家發(fā)現(xiàn)我哪里寫的不對,請務(wù)必通知我,讓我也明白為什么失?。≈x謝?。?/p>
第二種方式:繼承ZuulFilter
因?yàn)榈谝环N方式在https下失敗后,我嘗試了用zuulfilter實(shí)現(xiàn)cors的方式
一共需要兩個(gè)filiter:一個(gè)pre, 一個(gè)post
Pre-Filter:
@Component public class FirstFilter extends ZuulFilter { private Logger logger = LoggerFactory.getLogger(FirstFilter.class); @Override public String filterType() { /* pre:可以在請求被路由之前調(diào)用 route:在路由請求時(shí)候被調(diào)用 post:在route和error過濾器之后被調(diào)用 error:處理請求時(shí)發(fā)生錯(cuò)誤時(shí)被調(diào)用 * */ // 前置過濾器 return FilterConstants.PRE_TYPE; } @Override public int filterOrder() { //// 優(yōu)先級為0,數(shù)字越大,優(yōu)先級越低 return 0; } @Override public boolean shouldFilter() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); //只過濾OPTIONS 請求 if(request.getMethod().equals(RequestMethod.OPTIONS.name())){ return true; } return false; } @Override public Object run() { logger.debug("*****************FirstFilter run start*****************"); RequestContext ctx = RequestContext.getCurrentContext(); HttpServletResponse response = ctx.getResponse(); HttpServletRequest request = ctx.getRequest(); response.setHeader("Access-Control-Allow-Origin",request.getHeader("Origin")); response.setHeader("Access-Control-Allow-Credentials","true"); response.setHeader("Access-Control-Allow-Headers","authorization, content-type"); response.setHeader("Access-Control-Allow-Methods","POST,GET"); response.setHeader("Access-Control-Expose-Headers","X-forwared-port, X-forwarded-host"); response.setHeader("Vary","Origin,Access-Control-Request-Method,Access-Control-Request-Headers"); //不再路由 ctx.setSendZuulResponse(false); ctx.setResponseStatusCode(200); logger.debug("*****************FirstFilter run end*****************"); return null; } }
Pre-Filter 用來處理預(yù)處理OPTIONS請求,當(dāng)發(fā)現(xiàn)是OPTIONS請求的時(shí)候,給出跨域響應(yīng)頭,并且不對其進(jìn)行zuul路由,直接返回成功(200), 給前端服務(wù)允許跨域
post-Filter :
@Component public class PostFilter extends ZuulFilter { private Logger logger = LoggerFactory.getLogger(PostFilter.class); @Override public String filterType() { /* pre:可以在請求被路由之前調(diào)用 route:在路由請求時(shí)候被調(diào)用 post:在route和error過濾器之后被調(diào)用 error:處理請求時(shí)發(fā)生錯(cuò)誤時(shí)被調(diào)用 * */ // 前置過濾器 return FilterConstants.POST_TYPE; } @Override public int filterOrder() { //// 優(yōu)先級為0,數(shù)字越大,優(yōu)先級越低 return 2; } @Override public boolean shouldFilter() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); //過濾各種POST請求 if(request.getMethod().equals(RequestMethod.OPTIONS.name())){ return false; } return true; } @Override public Object run() { logger.debug("*****************PostFilter run start*****************"); RequestContext ctx = RequestContext.getCurrentContext(); HttpServletResponse response = ctx.getResponse(); HttpServletRequest request = ctx.getRequest(); response.setHeader("Access-Control-Allow-Origin",request.getHeader("Origin")); response.setHeader("Access-Control-Allow-Credentials","true"); response.setHeader("Access-Control-Expose-Headers","X-forwared-port, X-forwarded-host"); response.setHeader("Vary","Origin,Access-Control-Request-Method,Access-Control-Request-Headers"); //允許繼續(xù)路由 ctx.setSendZuulResponse(true); ctx.setResponseStatusCode(200); logger.debug("*****************PostFilter run end*****************"); return null; } }
Post-Filter 用來處理 預(yù)處理OPTIONS以外的請求,對于正常的請求,不但要給出跨域請求頭,還需要允許請求進(jìn)行路由(否則你的請求到這兒就結(jié)束啦),然后返回狀態(tài)碼200。(emmmm……這里要不要返回200,我覺得可能還要想一想……)
按照以上方式配置的話,方法一出現(xiàn)的問題,就得到了解決。服務(wù)A能夠正常請求服務(wù)B了
雖然是正常實(shí)現(xiàn)了需求,但是感覺還是存在很多疑惑,希望大家看到的話,能給我指出不足。一起討論!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/76601.html
摘要:類似這樣而在客戶端我們只需要定義一個(gè)預(yù)定好的回調(diào)函數(shù)即可。處理跨域請求得到的數(shù)據(jù)其中的是我們在客戶端定義好的在數(shù)據(jù)請求成功后要執(zhí)行的回調(diào)函數(shù)。 跨域產(chǎn)生的原因 跨域是由瀏覽器的同源策略引起的,即不同源(協(xié)議,域名,端口中其中有一個(gè)不同)的js是不能讀取對方的資源的。當(dāng)要網(wǎng)站中的js要請求其他網(wǎng)站的數(shù)據(jù)時(shí)就會(huì)產(chǎn)生跨域問題,就像下面這樣,瀏覽器會(huì)報(bào)錯(cuò)。 showImg(https://se...
摘要:由于第二種方法如今已經(jīng)采用的非常少,所以我們在這兒不做講解一帶填充的是一種可以在中繞過同源策略,并發(fā)起跨域請求的使用模式,可以啟動(dòng)的跨域請求同源策略有一個(gè)顯著的例外,腳本元素是可以規(guī)避檢查的。 講跨域之前,我們先來講同源策略(SOP),同源策略是網(wǎng)景公司提出的一個(gè)著名安全策略。所謂同源就是域名、協(xié)議、端口相同。例如http://www.12306.cn中,http就是超文本傳輸協(xié)議,1...
摘要:例外當(dāng)涉及到同源策略時(shí),有兩個(gè)主要的例外授信范圍兩個(gè)相互之間高度互信的域名,如公司域名,不遵守同源策略的限制。端口未將端口號(hào)加入到同源策略的組成部分之中,因此和屬于同源并且不受任何限制。 原文鏈接:http://www.devsai.com/2016/11/24/talk-CORS/ 同源策略(same origin policy) 1995年,同源政策由 Netscape 公司引入瀏...
摘要:前端基本功常見概念一點(diǎn)這里前端基本功常見概念二點(diǎn)這里前端基本功常見概念三點(diǎn)這里什么是原型鏈當(dāng)一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法時(shí)候就會(huì)產(chǎn)生一個(gè)原型鏈。函數(shù)式編程是聲明式而不是命令式,并且應(yīng)用程序狀態(tài)通過純函數(shù)流轉(zhuǎn)。 前端基本功-常見概念(一) 點(diǎn)這里前端基本功-常見概念(二) 點(diǎn)這里前端基本功-常見概念(三) 點(diǎn)這里 1.什么是原型鏈 當(dāng)一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方...
閱讀 2515·2021-11-15 11:36
閱讀 1260·2019-08-30 15:56
閱讀 2313·2019-08-30 15:53
閱讀 1103·2019-08-30 15:44
閱讀 714·2019-08-30 14:13
閱讀 1052·2019-08-30 10:58
閱讀 542·2019-08-29 15:35
閱讀 1368·2019-08-29 13:58