在Spring 5 Webflux中,配置CORS,可以通过自定义WebFilter实现:
注:此种写法需真实跨域访问,监控header中才会带相应属性。
代码实现方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
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); }; } } |
配置实现方式
网上还提到一种配置写法,实测好用:
1
2
3
4
5
6
7
8
9
|
spring: cloud: gateway: globalcors: corsConfigurations: '[/**]' : allowedOrigins: "*" allowedMethods: "*" allowedHeaders: "*" |
springcloud gateway 跨域的解决
springcloud gateway提供的自带的跨域过滤器有问题,前端还是会报跨域。zuul不会有这个问题。调试发现主要是游览器发送嗅探请求(OPTIONS)时,没有返回跨域的响应头,从而游览器报跨域问题。
验证
由于springcloud gateway为webflux与zuul不一样,同一个服务,采用spring内置的跨域过滤器,zuul可以通过而gateway报错。具体配置如下:
1、gateway跨域配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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
向容器中注入跨域过滤器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
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、实现一个过滤器,来做跨域允许
需要在响应头中加入以下信息
1
2
3
4
5
|
# 这个为请求头中的 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添加跨域响应头
1
2
3
4
|
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中方案,测试完美解决!
以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://wanghq.blog.csdn.net/article/details/88179626