gitway 添加依赖

This commit is contained in:
weiyachao 2023-09-21 17:46:39 +08:00
parent 8309b6d8ce
commit 4685991a2b
7 changed files with 310 additions and 1 deletions

View File

@ -49,7 +49,17 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,45 @@
package com.qiuguo.iot.gateway.config;
import com.qiuguo.iot.gateway.config.properties.CorsProperties;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
/**
* 全局跨域配置.
*
*/
@AutoConfiguration
@EnableConfigurationProperties(CorsProperties.class)
public class GlobalCorsConfiguration {
/**
* 允许跨域调用的过滤器.
*
* @param corsProperties 跨域配置
*/
@Bean
@ConditionalOnMissingBean(CorsFilter.class)
public CorsFilter corsFilter(CorsProperties corsProperties) {
CorsConfiguration config = new CorsConfiguration();
// 设置允许跨域访问的域名
config.setAllowedOriginPatterns(corsProperties.getAllowedOriginPatterns());
// 设置允许跨域访问的方法
config.setAllowedMethods(corsProperties.getAllowedMethods());
// 设置允许跨域访问的请求头
config.setAllowedHeaders(corsProperties.getAllowedHeaders());
config.setExposedHeaders(corsProperties.getExposedHeaders());
// 允许跨越发送cookie
config.setAllowCredentials(corsProperties.getAllowCredentials());
config.setMaxAge(corsProperties.getMaxAge());
// 对接口配置跨域设置
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}

View File

@ -0,0 +1,48 @@
package com.qiuguo.iot.gateway.config.properties;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 跨域配置.
*
* @author yangning
* @since 2022/11/7 14:45
*/
@Getter
@Setter
@ConfigurationProperties(prefix = "application.cors")
public class CorsProperties {
/**
* 允许跨域访问的域名.
*/
private List<String> allowedOriginPatterns;
/**
* 允许跨域访问的方法.
*/
private List<String> allowedMethods;
/**
* 允许跨域访问的请求头.
*/
private List<String> allowedHeaders;
/**
* 暴露的响应头.
*/
private List<String> exposedHeaders;
/**
* 是否允许跨域发送cookie.
*/
private Boolean allowCredentials = true;
/**
* 跨域访问有效期.
*/
private Long maxAge = 1800L;
}

View File

@ -0,0 +1,31 @@
package com.qiuguo.iot.gateway.config.properties;
import java.util.ArrayList;
import java.util.List;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
/**
* Xss配置.
*
* @author yangning
* @since 2023/4/7 18:31
*/
@Data
@Component
@RefreshScope
@ConfigurationProperties(prefix = "security.xss")
public class XssProperties {
/**
* Xss开关.
*/
private Boolean enabled;
/**
* 排除路径.
*/
private List<String> excludeUrls = new ArrayList<>();
}

View File

@ -0,0 +1,40 @@
package com.qiuguo.iot.gateway.filter;
import com.qiuguo.iot.gateway.util.WebFluxUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* 全局缓存获取body请求数据解决流不能重复读取问题.
*
* @author yangning
* @since 2022/12/14 16:07
*/
@Component
public class GlobalCacheRequestFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 只缓存json类型请求
// if (!WebFluxUtils.isJsonRequest(exchange)) {
// return chain.filter(exchange);
// }
return ServerWebExchangeUtils.cacheRequestBody(exchange, (serverHttpRequest) -> {
if (serverHttpRequest == exchange.getRequest()) {
return chain.filter(exchange);
}
return chain.filter(exchange.mutate().request(serverHttpRequest).build());
});
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}

View File

@ -0,0 +1,47 @@
package com.qiuguo.iot.gateway.handler;
import com.qiuguo.iot.gateway.util.WebFluxUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* 网关统一异常处理.
*
*/
@Slf4j
@Order(-1)
@Configuration
public class GatewayExceptionHandler implements ErrorWebExceptionHandler {
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
final ServerHttpResponse response = exchange.getResponse();
if (exchange.getResponse().isCommitted()) {
return Mono.error(ex);
}
String msg;
if (ex instanceof NotFoundException) {
msg = "服务未找到";
} else if (ex instanceof ResponseStatusException) {
ResponseStatusException responseStatusException = (ResponseStatusException) ex;
msg = responseStatusException.getMessage();
} else {
msg = "内部服务器错误";
}
log.error("[网关异常处理]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), ex.getMessage());
return WebFluxUtils.webFluxResponseWriter(response, msg);
}
}

View File

@ -0,0 +1,88 @@
package com.qiuguo.iot.gateway.util;
import com.alibaba.fastjson.JSON;
import java.util.HashMap;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* WebFlux 工具类.
*/
public class WebFluxUtils {
/**
* 是否是Json请求.
*
* @param exchange HTTP请求
*/
public static boolean isJsonRequest(ServerWebExchange exchange) {
String header = exchange.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
}
/**
* 设置webflux模型响应.
*
* @param response ServerHttpResponse
* @param value 响应内容
* @return Mono
*/
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, Object value) {
return webFluxResponseWriter(response, HttpStatus.OK, value, HttpStatus.INTERNAL_SERVER_ERROR.value());
}
/**
* 设置webflux模型响应.
*
* @param response ServerHttpResponse
* @param code 响应状态码
* @param value 响应内容
* @return Mono
*/
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, Object value, int code) {
return webFluxResponseWriter(response, HttpStatus.OK, value, code);
}
/**
* 设置webflux模型响应.
*
* @param response ServerHttpResponse
* @param status http状态码
* @param code 响应状态码
* @param value 响应内容
* @return Mono
*/
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, HttpStatus status, Object value,
int code) {
return webFluxResponseWriter(response, MediaType.APPLICATION_JSON_VALUE, status, value, code);
}
/**
* 设置webflux模型响应.
*
* @param response ServerHttpResponse
* @param contentType content-type
* @param status http状态码
* @param code 响应状态码
* @param value 响应内容
* @return Mono
*/
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, String contentType, HttpStatus status,
Object value, int code) {
response.setStatusCode(status);
response.getHeaders().add(HttpHeaders.CONTENT_TYPE, contentType);
HashMap<String, Object> map = new HashMap<>();
map.put("message", value.toString());
map.put("status", code);
map.put("code", "error");
map.put("timestamp", System.currentTimeMillis());
DataBuffer dataBuffer = response.bufferFactory().wrap(JSON.toJSONString(map).getBytes());
return response.writeWith(Mono.just(dataBuffer));
}
}