spring cloud gateway跨域全局CORS配置方式
在Spring 5 Webflux中,配置CORS,可以通過自定義WebFilter實現:
註:此種寫法需真實跨域訪問,監控header中才會帶相應屬性。
代碼實現方式
import org.springframework.http.HttpHeaders; 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 org.springframework.http.HttpMethod; import reactor.core.publisher.Mono; import static org.springframework.web.cors.CorsConfiguration.ALL; public class XXXApplication{ public static void main(String[] args) { SpringApplication.run(XXXApplication.class, args); } private static final String MAX_AGE = "18000L"; @Bean public WebFilter corsFilter() { return (ServerWebExchange ctx, WebFilterChain chain) -> { ServerHttpRequest request = ctx.getRequest(); if (!CorsUtils.isCorsRequest(request)) { return chain.filter(ctx); } HttpHeaders requestHeaders = request.getHeaders(); ServerHttpResponse response = ctx.getResponse(); HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod(); HttpHeaders headers = response.getHeaders(); headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin()); headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders()); if (requestMethod != null) { headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name()); } headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, ALL); headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE); if (request.getMethod() == HttpMethod.OPTIONS) { response.setStatusCode(HttpStatus.OK); return Mono.empty(); } return chain.filter(ctx); }; } }
配置實現方式
網上還提到一種配置寫法,實測好用:
spring: cloud: gateway: globalcors: corsConfigurations: '[/**]': allowedOrigins: "*" allowedMethods: "*" allowedHeaders: "*"
springcloud gateway 跨域的解決
springcloud gateway提供的自帶的跨域過濾器有問題,前端還是會報跨域。zuul不會有這個問題。調試發現主要是遊覽器發送嗅探請求(OPTIONS)時,沒有返回跨域的響應頭,從而遊覽器報跨域問題。
驗證
由於springcloud gateway為webflux與zuul不一樣,同一個服務,采用spring內置的跨域過濾器,zuul可以通過而gateway報錯。具體配置如下:
1、gateway跨域配置
spring: cloud: gateway: globalcors: cors-configurations: '[/**]': # 允許攜帶認證信息 # 允許跨域的源(網站域名/ip),設置*為全部 # 允許跨域請求裡的head字段,設置*為全部 # 允許跨域的method, 默認為GET和OPTIONS,設置*為全部 # 跨域允許的有效期 allow-credentials: true allowed-origins: '*' allowed-headers: Content-Type,Content-Length, Authorization, Accept,X-Requested-With allowed-methods: '*' exposed-headers: Content-Type,Content-Length, Authorization, Accept,X-Requested-With max-age: 3600
此配置無效,前端還是會報跨域問題,主要是前端發送OPTIONS請求時沒有返回跨域信息
2、zuul網關或者其它微服務servlet
向容器中註入跨域過濾器
import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.core.Ordered; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; /** * @author ZhouChuGang * @version 1.0 * @project langangkj-commonm * @date 2020/5/4 12:24 * @Description 跨域過濾器配置 */ @Slf4j @configuration @ConditionalOnMissingBean(CorsFilter.class) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) public class CorsFilterConfiguration { public CorsFilterConfiguration() { log.info("==========註入跨域過濾器============="); } @Bean("corsFilter") public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); // #允許向該服務器提交請求的URI,*表示全部允許 config.addAllowedOrigin(CorsConfiguration.ALL); // 允許cookies跨域 config.setAllowCredentials(true); // #允許訪問的頭信息,*表示全部 config.addAllowedHeader(CorsConfiguration.ALL); // 允許提交請求的方法,*表示全部允許 config.addAllowedMethod(CorsConfiguration.ALL); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } @Autowired @Qualifier("corsFilter") private CorsFilter corsFilter; /** * 配置跨域過濾器 */ @Bean public FilterRegistrationBean<CorsFilter> corsFilterRegistration() { FilterRegistrationBean<CorsFilter> registration = new FilterRegistrationBean<>(); registration.setFilter(corsFilter); registration.addUrlPatterns("/*"); registration.setName("corsFilter"); registration.setOrder(Ordered.HIGHEST_PRECEDENCE); return registration; } }
此方案可以完美解決跨域問題。但是springcloud gateway 不是servlet 規范。
解決方案
1、gateway後面的微服務實現跨域
跨域由網關後面的服務實現。
2、實現一個過濾器,來做跨域允許
需要在響應頭中加入以下信息
# 這個為請求頭中的 origin add_header 'Access-Control-Allow-Origin' '$http_origin' ; add_header 'Access-Control-Allow-Credentials' 'true' ; add_header 'Access-Control-Allow-Methods' 'PUT,POST,GET,DELETE,OPTIONS' ; add_header 'Access-Control-Allow-Headers' 'Content-Type,Content-Length,Authorization,Accept,X-Requested-With' ;
3、采用nginx做代理,配置跨域響應頭。(強烈推薦)
請求先到nginx,nginx再去請求gateway, 由nginx添加跨域響應頭
add_header 'Access-Control-Allow-Origin' '$http_origin' ; add_header 'Access-Control-Allow-Credentials' 'true' ; add_header 'Access-Control-Allow-Methods' 'PUT,POST,GET,DELETE,OPTIONS' ; add_header 'Access-Control-Allow-Headers' 'Content-Type,Content-Length,Authorization,Accept,X-Requested-With' ;
這裡本人為瞭方便,采用第3中方案,測試完美解決!
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- SpringBoot開發技巧之如何處理跨域請求CORS
- Java 如何解決跨域問題
- gateway網關與前端請求跨域問題的解決方案
- java後端解決跨域的幾種問題解決
- springboot 設置CorsFilter跨域不生效的解決