使用SpringCloudApiGateway之支持Cors跨域請(qǐng)求
問(wèn)題背景
公司的項(xiàng)目需要前后端分離,vue+java,這時(shí)候就需要支持Cors跨域請(qǐng)求了。最近對(duì)zuul進(jìn)行升級(jí),假如說(shuō)zuul是1.0的話(huà),api gateway就是2.0的網(wǎng)關(guān),支持ws等,基于NIO,各方面還是強(qiáng)大的。
解決方案
新建一個(gè)Configuration類(lèi)即可
import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.gateway.discovery.DiscoveryClientRouteDefinitionLocator; import org.springframework.cloud.gateway.route.RouteDefinitionLocator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.web.cors.reactive.CorsUtils; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Mono; /** * SpringApiGateway Cors */ @Configuration public class RouteConfiguration { //這里為支持的請(qǐng)求頭,如果有自定義的header字段請(qǐng)自己添加(不知道為什么不能使用*) private static final String ALLOWED_HEADERS = "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN,token,username,client"; private static final String ALLOWED_METHODS = "*"; private static final String ALLOWED_ORIGIN = "*"; private static final String ALLOWED_Expose = "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN,token,username,client"; private static final String MAX_AGE = "18000L"; @Bean public WebFilter corsFilter() { return (ServerWebExchange ctx, WebFilterChain chain) -> { ServerHttpRequest request = ctx.getRequest(); if (CorsUtils.isCorsRequest(request)) { ServerHttpResponse response = ctx.getResponse(); HttpHeaders headers = response.getHeaders(); headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN); headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS); headers.add("Access-Control-Max-Age", MAX_AGE); headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS); headers.add("Access-Control-Expose-Headers", ALLOWED_Expose); headers.add("Access-Control-Allow-Credentials", "true"); if (request.getMethod() == HttpMethod.OPTIONS) { response.setStatusCode(HttpStatus.OK); return Mono.empty(); } } return chain.filter(ctx); }; } /** * *如果使用了注冊(cè)中心(如:Eureka),進(jìn)行控制則需要增加如下配置 */ @Bean public RouteDefinitionLocator discoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient) { return new DiscoveryClientRouteDefinitionLocator(discoveryClient); } }
application.yml配置
官方文檔提及到還有另外一種方式,就是通過(guò)yml來(lái)配置。
spring: cloud: gateway: globalcors: corsConfigurations: '[/**]': allowedOrigins: "https://blog.csdn.net/moshowgame" allowedMethods: - GET
跨域解決方案(CORS)
1. 什么是跨域?
跨域問(wèn)題是出于瀏覽器的【同源策略】限制。同源策略(Sameoriginpolicy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會(huì)受到影響。
可以說(shuō)Web是構(gòu)建在同源策略基礎(chǔ)之上的,瀏覽器只是針對(duì)同源策略的一種實(shí)現(xiàn)。同源策略會(huì)阻止一個(gè)域的javascript腳本和另外一個(gè)域的內(nèi)容進(jìn)行交互。
所謂同源(即指在同一個(gè)域)就是兩個(gè)頁(yè)面具有相同的協(xié)議(protocol),主機(jī)(host)和端口號(hào)(port)
由于我們現(xiàn)在是采用的前后端分離的微服務(wù)架構(gòu),前端和后端必定存在跨域問(wèn)題。解決跨域問(wèn)題可以采用CORS。
2. CORS簡(jiǎn)介
CORS 是一個(gè) W3C 標(biāo)準(zhǔn),全稱(chēng)是"跨域資源共享"(Cross-origin resource sharing)。
CORS需要瀏覽器和服務(wù)器同時(shí)支持。但是目前基本上瀏覽器都支持,所以我們只要保證服務(wù)器端服務(wù)器實(shí)現(xiàn)了 CORS 接口,就可以跨源通信。
瀏覽器將CORS請(qǐng)求分成兩類(lèi):簡(jiǎn)單請(qǐng)求(simple request)和非簡(jiǎn)單請(qǐng)求(not-so-simple request)。
3. 具體解決方式
解決跨域問(wèn)題,就是在服務(wù)器端給響應(yīng)添加頭信息
Name | Required | Comments |
---|---|---|
Access-Control-Allow-Origin | 必填 | 允許請(qǐng)求的域 |
Access-Control-Allow-Methods | 必填 | 允許請(qǐng)求的方法 |
Access-Control-Allow-Headers | 可選 | 預(yù)檢請(qǐng)求后,告知發(fā)送請(qǐng)求需要有的頭部 |
Access-Control-Allow-Credentials | 可選 | 表示是否允許發(fā)送cookie,默認(rèn)false; |
Access-Control-Max-Age | 可選 | 本次預(yù)檢的有效期,單位:秒; |
3.1 在Spring Boot 中解決
在spring boot中給我們提供了 @CrossOrigin 注解用于解決跨域問(wèn)題。
使用場(chǎng)景要求:jdk1.8+、Spring4.2+
只需要在我們需要的controller上加@CrossOrigin
@RestController //實(shí)現(xiàn)跨域注解 //origin="*"代表所有域名都可訪(fǎng)問(wèn) //maxAge飛行前響應(yīng)的緩存持續(xù)時(shí)間的最大年齡,簡(jiǎn)單來(lái)說(shuō)就是Cookie的有效期 單位為秒若maxAge是負(fù)數(shù),則代表為臨時(shí)Cookie,不會(huì)被持久化,Cookie信息保存在瀏覽器內(nèi)存中,瀏覽器關(guān)閉Cookie就消失 @CrossOrigin(origins = "*",maxAge = 3600) @RequestMapping("/album") public class AlbumController {}
3.2 在spring Cloud中解決
只需要在spring Cloud Gateway 服務(wù)中添加配置就行
spring: application: name: system-gateway cloud: gateway: globalcors: cors-configurations: '[/**]': # 匹配所有請(qǐng)求 allowedOrigins: "*" #跨域處理 允許所有的域 allowedMethods: # 支持的方法 - GET - POST - PUT - DELETE
當(dāng)然也可以自己利用Gateway的攔截器來(lái)手動(dòng)添加相應(yīng)的頭信息
default-filters: - AddResponseHeader=Access-Control-Allow-Credentials,true - AddResponseHeader=Access-Control-Allow-Headers,access-control-allow-origin - AddResponseHeader=Access-Control-Allow-Methods,GET - AddResponseHeader=Access-Control-Allow-Origin,* - AddResponseHeader=Access-Control-Allow-Age,3600
3.3 在Nginx中解決
location /example { if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin *; add_header Access-Control-Max-Age 1728000; add_header Access-Control-Allow-Methods GET,POST,OPTIONS; add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header Content-Type' 'text/plain; charset=utf-8'; add_header Content-Length 0 ; return 204; } + if ($http_origin ~* (https?://(.+\.)?(example\.com$))) { + add_header Access-Control-Allow-Origin $http_origin; + add_header Access-Control-Allow-Credentials true; + add_header Access-Control-Allow-Methods GET,POST,OPTIONS; + add_header Access-Control-Expose-Headers Content-Length,Content-Range; + } proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://127.0.0.1:8080/; }
解釋?zhuān)?/strong>
if ($request_method = 'OPTIONS') {...} 當(dāng)請(qǐng)求方法為 OPTIONS 時(shí):
- 添加允許源 Access-Control-Allow-Origin 為 * (可根據(jù)業(yè)務(wù)需要更改)
- 添加緩存時(shí)長(zhǎng) Access-Control-Max-Age,當(dāng)下次請(qǐng)求時(shí),無(wú)需再發(fā)送 OPTIONS 請(qǐng)求
- 添加允許的方法,允許的首部
- 添加一個(gè)內(nèi)容長(zhǎng)度為0,類(lèi)型為 text/plain; charset=utf-8 , 返回狀態(tài)碼為 204 的首部
if ($http_origin ~* (https?://(.+\.)?(example\.com$))) {...}, 當(dāng) origin 為合法域名(可根據(jù)業(yè)務(wù)調(diào)整或去除合法域名驗(yàn)證)時(shí):
- 添加允許源Access-Control-Allow-Origin為 $http_origin (可根據(jù)業(yè)務(wù)需要更改)
- 添加允許認(rèn)證Access-Control-Allow-Credentials為 true ,允許接收客戶(hù)端 Cookie(可根據(jù)業(yè)務(wù)需要更改。 但要注意,當(dāng)設(shè)置為true時(shí),Access-Control-Allow-Origin 不允許設(shè)置為 *)
- 添加允許的方法,暴露的首部
至此,完成跨域請(qǐng)求正確響應(yīng)。
以上,是對(duì)跨域請(qǐng)求在Web Server的解決方案,主要是通過(guò)響應(yīng) OPTIONS 方法和添加允許源來(lái)解決。希望能給大家一個(gè)參考,也希望大家多多支持腳本之家
相關(guān)文章
Java源碼解析之Gateway請(qǐng)求轉(zhuǎn)發(fā)
今天給大家?guī)?lái)的是關(guān)于Java的相關(guān)知識(shí),文章圍繞著Gateway請(qǐng)求轉(zhuǎn)發(fā)展開(kāi),文中有非常詳細(xì)介紹及代碼示例,需要的朋友可以參考下2021-06-06SpringMVC使用ResponseEntity實(shí)現(xiàn)文件上傳下載
這篇文章主要為大家介紹了SpringMVC使用ResponseEntity實(shí)現(xiàn)文件上傳下載,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05java用arraycopy實(shí)現(xiàn)多擊事件
這篇文章主要介紹了java用arraycopy實(shí)現(xiàn)多擊事件的多種方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11一小時(shí)迅速入門(mén)Mybatis之初識(shí)篇
這篇文章主要介紹了迅速入門(mén)Mybatis之初識(shí)篇,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09使用IDEA創(chuàng)建一個(gè)vert.x項(xiàng)目的方法
這篇文章主要介紹了使用IDEA創(chuàng)建一個(gè)vert.x項(xiàng)目的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-09-09BUUCTF-easy java WEB-INF/web.xml泄露漏洞及其利用方式
這篇文章主要介紹了BUUCTF-easy java WEB-INF/web.xml泄露漏洞及其利用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07Java實(shí)現(xiàn)一個(gè)簡(jiǎn)單計(jì)算器
這篇文章主要介紹了Java實(shí)現(xiàn)一個(gè)簡(jiǎn)單計(jì)算器,文章我圍繞實(shí)現(xiàn)簡(jiǎn)單計(jì)算器的相關(guān)代碼展現(xiàn)全文,具有一定的參考價(jià)值,需要的小伙伴可以參考一下,2022-01-01解析spring-security權(quán)限控制和校驗(yàn)的問(wèn)題
這篇文章主要介紹了解析spring-security權(quán)限控制和校驗(yàn)的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03Java利用數(shù)組隨機(jī)抽取幸運(yùn)觀眾如何實(shí)現(xiàn)
這篇文章主要介紹了Java利用數(shù)組隨機(jī)抽取幸運(yùn)觀眾如何實(shí)現(xiàn),需要的朋友可以參考下2014-02-02