spring-cloud-gateway 解决cors跨域和重复header头的两种解决方案
配置项解决冲突# 这一段前面的配置是处理跨域的,本文处理重复header的请看最后一条配置spring.cloud.gateway.globalcors.cors-configurations.[/**].allow-credentials=truespring.cloud.gateway.globalcors.cors-configurations.[/**].allowed-headers[0
·
配置项解决冲突
# 这一段前面的配置是处理跨域的,本文处理重复header的请看最后一条配置
spring.cloud.gateway.globalcors.cors-configurations.[/**].allow-credentials=true
spring.cloud.gateway.globalcors.cors-configurations.[/**].allowed-headers[0]=*
spring.cloud.gateway.globalcors.cors-configurations.[/**].allowed-methods[0]=*
spring.cloud.gateway.globalcors.cors-configurations.[/**].allowed-origins[0]=*
spring.cloud.gateway.globalcors.cors-configurations.[/**].max-age=1800
# 相同header多个值时的处理方式,三种规则可选(RETAIN_FIRST|RETAIN_UNIQUE|RETAIN_LAST)
spring.cloud.gateway.default-filters[0]=DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials, RETAIN_FIRST
代码解决重复header头的问题和跨域问题:
package com.xxxxxx.komoe.mng.api.filter;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.core.Ordered;
import reactor.core.publisher.Mono;
import com.xxxxxx.komoe.mng.api.utils.JacksonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import java.util.*;
@Slf4j
@Component("corsResponseHeaderFilter")
public class CorsResponseHeaderFilter implements GlobalFilter, Ordered {
@Override
public int getOrder() {
// 指定此过滤器位于NettyWriteResponseFilter之后
// 即待处理完响应体后接着处理响应头
return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER + 1;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
try {
Set<Map.Entry<String, List<String>>> beforeHeaders = exchange.getResponse().getHeaders().entrySet();
log.info("处理前的header头={}", JacksonUtils.parseToJson(beforeHeaders));
return chain.filter(exchange).then(
Mono.defer(() -> {
exchange.getResponse().getHeaders().entrySet().stream()
.filter(kv -> (kv.getValue() != null && kv.getValue().size() > 1))
/*.filter(kv -> (kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)|| kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)))*/
.forEach(
kv -> {
// 重新填入对应值
log.info("key={},value={}", JacksonUtils.parseToJson(kv.getKey()), JacksonUtils.parseToJson(kv.getValue()));
kv.setValue(new ArrayList<String>() {{
add(kv.getValue().get(0));
}});
});
Set<Map.Entry<String, List<String>>> entries2 = exchange.getResponse().getHeaders().entrySet();
String s1 = JacksonUtils.parseToJson(entries2);
log.info("处理完毕的header头={}", s1);
return chain.filter(exchange);
}));
} catch (Exception e) {
log.error("去除重复请求头error,{},{}",e);
} finally {
}
return chain.filter(exchange);
}
}
package com.xxxxxxxx.komoe.mng.api.filter;
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;
@Configuration
public class CorsConfiguration {
private static final String ALLOWED_HEADERS = "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN,token,username,client,Origin,No-Cache,X-Requested-With,If-Modified-Since,Pragma,Last-Modified,Cache-Control,Expires,Access-Control-Allow-Credentials,Biligame-Request-Id,request-game-id,request-game-base-id,request-account-domain";
private static final String ALLOWED_METHODS = "*";
private static final String ALLOWED_METHODS_TEST = "GET,POST,OPTIONS";
private static final String ALLOWED_ORIGIN = "*";
private static final String ALLOWED_EXPOSE = "*";
private static final String MAX_AGE = "3600";
@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();
//todo 如果后续需要由我们来处理get请求的跨域问题,则将上面的代码处理即可....
/*// 配置为*
headers.set("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
headers.add("Access-Control-Allow-Credentials", "true");
// 配置为*
headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
// "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN,token,username,client,
// Origin,No-Cache,X-Requested-With,If-Modified-Since,Pragma,Last-Modified,Cache-Control,Expires";
headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
// 配置为
headers.add("Access-Control-Expose-Headers", ALLOWED_EXPOSE);
// 配置为 3600
//第一次是浏览器使用OPTIONS方法发起一个预检请求 每1800秒才会有一次
headers.add("Access-Control-Max-Age", MAX_AGE);*/
if (request.getMethod() == HttpMethod.OPTIONS) {
// 配置为*
headers.set("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
headers.add("Access-Control-Allow-Credentials", "true");
// 配置为*
headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
headers.add("Access-Control-Expose-Headers", ALLOWED_EXPOSE);
/**Access-Control-Max-Age 限制下次的时间
*第一次是浏览器使用OPTIONS方法发起一个预检请求
*浏览器会限制从脚本发起的跨域HTTP请求(比如异步请求GET, POST, PUT, DELETE, OPTIONS等等),所以浏览器会向所请求的服务器发起两次请求,
*第一次是浏览器使用OPTIONS方法发起一个预检请求,第二次才是真正的异步请求,第一次的预检请求获知服务器是否允许该跨域请求
*如果允许,才发起第二次真实的请求;如果不允许,则拦截第二次请求。
* */
headers.add("Access-Control-Max-Age", MAX_AGE);
/**header头 (206, "Partial Content")*/
response.setStatusCode(HttpStatus.PARTIAL_CONTENT);
return Mono.empty();
}
}
return chain.filter(ctx);
};
}
}
更多推荐
已为社区贡献1条内容
所有评论(0)