diff --git a/api-gateway/pom.xml b/api-gateway/pom.xml
new file mode 100644
index 0000000..0cee000
--- /dev/null
+++ b/api-gateway/pom.xml
@@ -0,0 +1,99 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.6.3
+
+
+
+ 3.1.1
+ 2.6.3
+ ${spring.boot.version}
+
+ api-gateway
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-gateway
+ ${spring.cloud.version}
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+ 2021.0.1.0
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-config
+ 2021.0.1.0
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-bootstrap
+ ${spring.cloud.version}
+
+
+ org.springframework.cloud
+ spring-cloud-context
+ ${spring.cloud.version}
+
+
+ org.springframework.cloud
+ spring-cloud-loadbalancer
+ ${spring.cloud.version}
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+ ${spring.boot.version}
+
+
+ org.projectlombok
+ lombok
+
+
+ com.alibaba
+ fastjson
+ 1.2.83
+ compile
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis-reactive
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+ org.aspectj
+ aspectjweaver
+
+
+
+
+
+ ${project.artifactId}
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring.boot.maven.plugin.version}
+
+
+
+
+
\ No newline at end of file
diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/GatewayApplication.java b/api-gateway/src/main/java/com/heyu/api/gateway/GatewayApplication.java
new file mode 100644
index 0000000..d1a7392
--- /dev/null
+++ b/api-gateway/src/main/java/com/heyu/api/gateway/GatewayApplication.java
@@ -0,0 +1,18 @@
+package com.heyu.api.gateway;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+
+/**
+ * https://blog.csdn.net/qq_38380025/article/details/84936466
+ */
+@SpringBootApplication
+@EnableDiscoveryClient
+public class GatewayApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(GatewayApplication.class, args);
+ }
+
+}
diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/config/CustomLoadBalancerConfiguration.java b/api-gateway/src/main/java/com/heyu/api/gateway/config/CustomLoadBalancerConfiguration.java
new file mode 100644
index 0000000..21f34b0
--- /dev/null
+++ b/api-gateway/src/main/java/com/heyu/api/gateway/config/CustomLoadBalancerConfiguration.java
@@ -0,0 +1,30 @@
+package com.heyu.api.gateway.config;
+
+import com.alibaba.cloud.nacos.discovery.NacosServiceDiscovery;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.loadbalancer.core.CachingServiceInstanceListSupplier;
+import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
+import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
+import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+
+@Configuration(proxyBeanMethods = false)
+@AutoConfigureAfter({CachingServiceInstanceListSupplier.class, NacosServiceDiscovery.class})
+public class CustomLoadBalancerConfiguration {
+
+
+ @Bean
+ ReactorLoadBalancer randomLoadBalancer(Environment environment,
+ LoadBalancerClientFactory loadBalancerClientFactory) {
+ String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
+
+ //这里返回了我自己定义的方法
+ return new MyRandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
+
+ }
+
+
+}
diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/config/GatewayConfiguration.java b/api-gateway/src/main/java/com/heyu/api/gateway/config/GatewayConfiguration.java
new file mode 100644
index 0000000..cf8aa0d
--- /dev/null
+++ b/api-gateway/src/main/java/com/heyu/api/gateway/config/GatewayConfiguration.java
@@ -0,0 +1,16 @@
+package com.heyu.api.gateway.config;
+
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * XXX
+ *
+ * @author weiyachao
+ * @since 2023/9/22 17:35
+ */
+@Configuration
+public class GatewayConfiguration {
+
+
+
+}
diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/config/GlobalCorsConfiguration.java b/api-gateway/src/main/java/com/heyu/api/gateway/config/GlobalCorsConfiguration.java
new file mode 100644
index 0000000..99fc8d1
--- /dev/null
+++ b/api-gateway/src/main/java/com/heyu/api/gateway/config/GlobalCorsConfiguration.java
@@ -0,0 +1,41 @@
+package com.heyu.api.gateway.config;
+
+import com.heyu.api.gateway.config.properties.CorsProperties;
+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);
+ }
+}
diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/config/MyLoadBalanceAutoConfiguration.java b/api-gateway/src/main/java/com/heyu/api/gateway/config/MyLoadBalanceAutoConfiguration.java
new file mode 100644
index 0000000..c493d5b
--- /dev/null
+++ b/api-gateway/src/main/java/com/heyu/api/gateway/config/MyLoadBalanceAutoConfiguration.java
@@ -0,0 +1,18 @@
+package com.heyu.api.gateway.config;
+
+import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
+
+/**
+ *
+ * @author Admin-WPG
+ *
+ */
+// https://blog.csdn.net/agulahaha/article/details/130783152
+@LoadBalancerClients(defaultConfiguration = CustomLoadBalancerConfiguration.class)
+public class MyLoadBalanceAutoConfiguration {
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/config/MyRandomLoadBalancer.java b/api-gateway/src/main/java/com/heyu/api/gateway/config/MyRandomLoadBalancer.java
new file mode 100644
index 0000000..660d4cf
--- /dev/null
+++ b/api-gateway/src/main/java/com/heyu/api/gateway/config/MyRandomLoadBalancer.java
@@ -0,0 +1,93 @@
+package com.heyu.api.gateway.config;
+
+import com.google.common.collect.Lists;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.client.loadbalancer.DefaultResponse;
+import org.springframework.cloud.client.loadbalancer.EmptyResponse;
+import org.springframework.cloud.client.loadbalancer.Request;
+import org.springframework.cloud.client.loadbalancer.Response;
+import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
+import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
+import org.springframework.cloud.loadbalancer.core.SelectedInstanceCallback;
+import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
+import reactor.core.publisher.Mono;
+
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * @author wutao
+ * @description 自定义负载均衡
+ * @date 2021-08-27
+ * 自定义实现,就是去实现这个ReactorServiceInstanceLoadBalancer接口。
+ *
+ * 默认实现的随机负载、轮训负载可查看RandomLoadBalancer、RoundRobinLoadBalancer类
+ *
+ */
+public class MyRandomLoadBalancer implements ReactorServiceInstanceLoadBalancer {
+
+ private static final Log log = LogFactory.getLog(MyRandomLoadBalancer.class);
+
+ private final String serviceId;
+
+ private ObjectProvider serviceInstanceListSupplierProvider;
+
+ private final static String DEPLOY_SERVER_IPS = "ips";
+
+ /**
+ * @param serviceInstanceListSupplierProvider a provider of
+ * {@link ServiceInstanceListSupplier} that will be used to get available instances
+ * @param serviceId id of the service for which to choose an instance
+ */
+ public MyRandomLoadBalancer(ObjectProvider serviceInstanceListSupplierProvider,
+ String serviceId) {
+ this.serviceId = serviceId;
+ this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public Mono> choose(Request request) {
+ ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
+ .getIfAvailable(NoopServiceInstanceListSupplier::new);
+
+ return supplier.get(request).next()
+ .map(serviceInstances -> processInstanceResponse(supplier, serviceInstances));
+ }
+
+ private Response processInstanceResponse(ServiceInstanceListSupplier supplier,
+ List serviceInstances) {
+ List services = Lists.newArrayList();
+ services.addAll(serviceInstances);
+ for (ServiceInstance server : serviceInstances) {
+ String hostPost = new StringBuffer(server.getHost()).append("_").append(server.getPort()).toString();
+ log.info("MyRandomLoadBalancer hostPost:" + hostPost);
+ }
+
+ Response serviceInstanceResponse = getInstanceResponse(services);
+ if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
+ ((SelectedInstanceCallback) supplier).selectedServiceInstance(serviceInstanceResponse.getServer());
+ }
+ return serviceInstanceResponse;
+ }
+
+
+
+ private Response getInstanceResponse(List instances) {
+ if (instances.isEmpty()) {
+ if (log.isWarnEnabled()) {
+ log.warn("No servers available for service: " + serviceId);
+ }
+ return new EmptyResponse();
+ }
+
+ int index = ThreadLocalRandom.current().nextInt(instances.size());
+
+ ServiceInstance instance = instances.get(index);
+ return new DefaultResponse(instance);
+ }
+
+}
diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/config/RedisConfig.java b/api-gateway/src/main/java/com/heyu/api/gateway/config/RedisConfig.java
new file mode 100644
index 0000000..de0032b
--- /dev/null
+++ b/api-gateway/src/main/java/com/heyu/api/gateway/config/RedisConfig.java
@@ -0,0 +1,40 @@
+package com.heyu.api.gateway.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+/**
+ * Created by wutao on 2019/5/5.
+ */
+@Configuration
+public class RedisConfig {
+
+ @Bean(name={"stringRedisTemplate"})
+ public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory){
+ StringRedisTemplate redisTemplate = new StringRedisTemplate();
+ redisTemplate.setConnectionFactory(factory);
+ return redisTemplate;
+ }
+
+ @Bean
+ public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
+ RedisTemplate redisTemplate = new RedisTemplate<>();
+ redisTemplate.setKeySerializer(new StringRedisSerializer());
+ redisTemplate.setHashKeySerializer(new StringRedisSerializer());
+ redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
+ redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
+ redisTemplate.setConnectionFactory(factory);
+ return redisTemplate;
+ }
+
+ @Bean
+ public ValueOperations valueOperations(RedisTemplate redisTemplate) {
+ return redisTemplate.opsForValue();
+ }
+}
diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/config/SecurityConfig.java b/api-gateway/src/main/java/com/heyu/api/gateway/config/SecurityConfig.java
new file mode 100644
index 0000000..9a8d027
--- /dev/null
+++ b/api-gateway/src/main/java/com/heyu/api/gateway/config/SecurityConfig.java
@@ -0,0 +1,33 @@
+package com.heyu.api.gateway.config;
+
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
+import org.springframework.security.config.web.server.ServerHttpSecurity;
+import org.springframework.security.web.server.SecurityWebFilterChain;
+
+@Configuration
+@EnableGlobalMethodSecurity(prePostEnabled = true)
+@EnableWebFluxSecurity
+public class SecurityConfig {
+
+ @Bean
+ public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity httpSecurity){
+ httpSecurity
+ .authorizeExchange()
+ //.pathMatchers("/actuator/**").denyAll()
+ .pathMatchers("/**").permitAll()
+ .pathMatchers(HttpMethod.OPTIONS).permitAll()
+ .anyExchange().authenticated()
+ .and()
+ .csrf()
+ .disable()
+ .cors();
+ return httpSecurity.build();
+ }
+}
+
+
diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/config/properties/CorsProperties.java b/api-gateway/src/main/java/com/heyu/api/gateway/config/properties/CorsProperties.java
new file mode 100644
index 0000000..60c67f3
--- /dev/null
+++ b/api-gateway/src/main/java/com/heyu/api/gateway/config/properties/CorsProperties.java
@@ -0,0 +1,48 @@
+package com.heyu.api.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 allowedOriginPatterns;
+
+ /**
+ * 允许跨域访问的方法.
+ */
+ private List allowedMethods;
+
+ /**
+ * 允许跨域访问的请求头.
+ */
+ private List allowedHeaders;
+
+ /**
+ * 暴露的响应头.
+ */
+ private List exposedHeaders;
+
+ /**
+ * 是否允许跨域发送cookie.
+ */
+ private Boolean allowCredentials = true;
+
+ /**
+ * 跨域访问有效期.
+ */
+ private Long maxAge = 1800L;
+}
diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/config/properties/LoadBalanceProperties.java b/api-gateway/src/main/java/com/heyu/api/gateway/config/properties/LoadBalanceProperties.java
new file mode 100644
index 0000000..a67c27a
--- /dev/null
+++ b/api-gateway/src/main/java/com/heyu/api/gateway/config/properties/LoadBalanceProperties.java
@@ -0,0 +1,4 @@
+package com.heyu.api.gateway.config.properties;
+
+public class LoadBalanceProperties {
+}
diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/config/properties/XssProperties.java b/api-gateway/src/main/java/com/heyu/api/gateway/config/properties/XssProperties.java
new file mode 100644
index 0000000..be149f3
--- /dev/null
+++ b/api-gateway/src/main/java/com/heyu/api/gateway/config/properties/XssProperties.java
@@ -0,0 +1,41 @@
+package com.heyu.api.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 excludeUrls = new ArrayList<>();
+
+ /**
+ * 访问ip
+ */
+ private String authIP;
+
+ /**
+ * IP允许访问的url
+ */
+ private List authUrls = new ArrayList<>();
+}
diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/filter/AuthWebFilter.java b/api-gateway/src/main/java/com/heyu/api/gateway/filter/AuthWebFilter.java
new file mode 100644
index 0000000..e4ce050
--- /dev/null
+++ b/api-gateway/src/main/java/com/heyu/api/gateway/filter/AuthWebFilter.java
@@ -0,0 +1,265 @@
+package com.heyu.api.gateway.filter;
+
+import com.alibaba.cloud.commons.lang.StringUtils;
+import com.heyu.api.gateway.config.properties.XssProperties;
+import com.heyu.api.gateway.util.ApiConstants;
+import com.heyu.api.gateway.util.Log4Constans;
+import com.heyu.api.gateway.util.OrderUtils;
+import com.heyu.api.gateway.util.UserAuthContains;
+import lombok.extern.slf4j.Slf4j;
+import org.reactivestreams.Publisher;
+import org.slf4j.MDC;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.buffer.DataBuffer;
+import org.springframework.core.io.buffer.DataBufferFactory;
+import org.springframework.core.io.buffer.DataBufferUtils;
+import org.springframework.core.io.buffer.DefaultDataBufferFactory;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.ObjectUtils;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.WebFilter;
+import org.springframework.web.server.WebFilterChain;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import reactor.util.context.Context;
+
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+/**
+ *
+ *
*日志配置
+ * @author wulin
+ * @since 2023-08-07
+ *
+ * https://blog.csdn.net/qq_26274037/article/details/127800559
+ */
+@Configuration
+@Slf4j
+public class AuthWebFilter implements WebFilter {
+ private static final String UNKNOWN = "unknown";
+ private static final String LOCALHOST = "127.0.0.1";
+ private static final String SEPARATOR = ",";
+
+ //由nginx配置透传过来
+ private static final String HEADER_X_FORWARDED_FOR = "X-Forwarded-For";
+ private static final String HEADER_PROXY_CLIENT_IP = "Proxy-Client-IP";
+ private static final String HEADER_WL_PROXY_CLIENT_IP = "WL-Proxy-Client-IP";
+
+
+ @Autowired
+ XssProperties xssProperties;
+
+
+
+
+ @Override
+ public Mono filter(ServerWebExchange exchange, WebFilterChain chain) {
+ long startTime = System.currentTimeMillis();
+ ServerHttpRequest request = exchange.getRequest();
+ String traceId = OrderUtils.getUserPoolOrder();
+ String requestId = request.getId();//请求id
+ MDC.put(Log4Constans.TRACE_ID, traceId);
+ String url = request.getPath().toString();
+ URI URIAll = request.getURI();
+ String uri = URIAll.getPath();
+ if("/favicon.ico".equals(uri)){
+ ServerHttpResponse response = exchange.getResponse();
+ DataBuffer bodyDataBuffer = response.bufferFactory().wrap("".getBytes());
+ response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
+ return response.writeWith(Mono.just(bodyDataBuffer));
+ }
+
+ HttpHeaders httpHeaders = request.getHeaders();
+ List paths = httpHeaders.get(ApiConstants.X_FORWARDED_PATH);
+ String xForwardedPath = null;
+ if (!CollectionUtils.isEmpty(paths) && uri.equals("/")) {
+ String path = paths.get(0);
+ xForwardedPath = path;
+ }
+
+ String realIpAddress = getRealIpAddress(request);
+ String m = request.getMethod().toString();
+ log.info("AuthWebFilter api start time:{} ip:{} method:{} url:{},uri:{} param:{} headers:{}",
+ startTime,
+ realIpAddress,
+ m,
+ request.getPath(),
+ uri,
+ request.getQueryParams(),
+ httpHeaders
+ );
+
+ if(xssProperties.getEnabled()) {
+ if (xssProperties.getAuthIP() != null && xssProperties.getAuthIP().contains(realIpAddress)) {
+ log.info("白名单IP,免验签");
+ return continueRequest(exchange, chain, realIpAddress, requestId, startTime,traceId,xForwardedPath);
+ }
+ if (xssProperties.getExcludeUrls().contains(url)) {
+ log.info("排除免签url内,直接通过");
+ return continueRequest(exchange, chain, realIpAddress, requestId, startTime,traceId,xForwardedPath);
+ }
+ if (xssProperties.getAuthUrls().size() > 0) {
+ for (String aurl : xssProperties.getAuthUrls()) {
+ if (url.contains(aurl)) {
+ log.info("免登陆url,免验签");
+ return continueRequest(exchange, chain, realIpAddress, requestId, startTime,traceId,xForwardedPath);
+
+ }
+ }
+ }
+ String api_token = exchange.getRequest().getHeaders().getFirst(UserAuthContains.API_TOKEN);
+ String api_type = exchange.getRequest().getHeaders().getFirst(UserAuthContains.API_TYPE);
+ // String key = RedisConstans.IOT_TOKEN.concat(api_token);
+ // return reactiveRedisTemplate.getExpire(key).map(Duration::getSeconds).flatMap(ttl -> {
+ // if (ttl == -1) {
+ // // 用户没登陆
+ // return Mono.error(new RuntimeException("未登录"));
+ // } else if (ttl <= 3600) {
+ // // token 将要失效
+ // return reactiveRedisTemplate.expire(key, Duration.ofDays(7)).then(chain.filter(exchange));
+ // } else {
+ // // 正常登录
+ // return chain.filter(exchange);
+ // }
+ // });
+ if (ObjectUtils.isEmpty(api_token) || ObjectUtils.isEmpty(api_type)) {
+ log.info("未传输token和type,需要登录");
+ return Mono.error(new RuntimeException("未登录"));
+ }
+ return continueRequest(exchange, chain, realIpAddress, requestId, startTime,traceId,xForwardedPath);
+ }
+ log.info("未开启xss验签认证");
+
+ return continueRequest(exchange, chain, realIpAddress, requestId, startTime,traceId,xForwardedPath);
+ }
+
+
+ private Mono continueRequest(ServerWebExchange exchange, WebFilterChain chain, String customerIp, String requestId,
+ long startTime,String traceId,String xForwardedPath){
+ ServerWebExchange.Builder ex = exchange.mutate();
+ ex.response(getResponse(exchange, requestId,traceId));
+ ex.request(getRequest(exchange, customerIp, requestId,traceId,xForwardedPath));
+
+ return chain.filter(ex.build()).contextWrite(context -> {
+ Context contextTmp = context.put(Log4Constans.TRACE_ID, traceId);
+ return contextTmp;
+ }).doFinally(single ->{
+ long endTime = System.currentTimeMillis();
+ log.info("api end time:{}, total time:{}", endTime, endTime - startTime);
+ MDC.remove(LogMdcConfiguration.PRINT_LOG_ID);
+ });
+ }
+
+ private ServerHttpResponse getResponse(ServerWebExchange exchange, String requestId,String traceId){
+ ServerHttpResponse response = exchange.getResponse();
+ return new ServerHttpResponseDecorator(response){
+ @Override
+ public Mono writeWith(Publisher extends DataBuffer> body){
+ MDC.put(Log4Constans.TRACE_ID, traceId);
+ if (body instanceof Flux) {
+ Flux extends DataBuffer> fluxBody = Flux.from(body);
+ return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
+ MDC.put(Log4Constans.TRACE_ID, traceId);
+ DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
+ DataBuffer joinBuffer = dataBufferFactory.join(dataBuffers);
+ byte[] returnContent = new byte[joinBuffer.readableByteCount()];
+ joinBuffer.read(returnContent);
+ DataBufferUtils.release(joinBuffer);
+ String returnStr = new String(returnContent, StandardCharsets.UTF_8);
+ log.info("response:{}", returnStr);
+ return response.bufferFactory().wrap(returnContent);
+ }));
+ }else if(body instanceof Mono){
+ Mono monoBody = Mono.from(body);
+ return super.writeWith(monoBody.map(dataBuffer -> {
+ MDC.put(Log4Constans.TRACE_ID, traceId);
+ log.info("response:{}", dataBuffer.toString(StandardCharsets.UTF_8));
+ return response.bufferFactory().wrap(dataBuffer.toString(StandardCharsets.UTF_8).getBytes());
+ }));
+ }
+ return super.writeWith(body);
+ }
+ };
+ }
+
+
+ private ServerHttpRequest getRequest(ServerWebExchange exchange, String customerIp, String requestId, String traceId, String xForwardedPath) {
+ ServerHttpRequest request = exchange.getRequest();
+ if (StringUtils.isNotEmpty(xForwardedPath)) {
+ String originXForwardedPath = xForwardedPath;
+ if (xForwardedPath.contains(ApiConstants.API_USER)) {
+ xForwardedPath = "/" + ApiConstants.API_USER + xForwardedPath.split(ApiConstants.API_USER)[1];
+ }
+ log.info("getRequest xForwardedPath is not null originXForwardedPath:{},xForwardedPath:{}",originXForwardedPath, xForwardedPath);
+ request = request.mutate().path(xForwardedPath).build();
+ }
+
+ ServerHttpRequest newRequest = new ServerHttpRequestDecorator(request) {
+ /*@Override
+ public Flux getBody() {
+ Flux body = this.getDelegate().getBody();
+ return body.map(dataBuffer -> {
+ log.info("request:{}", dataBuffer.toString(StandardCharsets.UTF_8));
+ return dataBuffer;
+ });
+ }*/
+ @Override
+ public HttpHeaders getHeaders() {
+ HttpHeaders httpHeaders = new HttpHeaders();
+ httpHeaders.putAll(super.getHeaders());
+ httpHeaders.set(HEADER_X_FORWARDED_FOR, customerIp);
+ httpHeaders.set(Log4Constans.IP, customerIp);
+ httpHeaders.set(Log4Constans.TRACE_ID, traceId);
+ return httpHeaders;
+ }
+ };
+ return newRequest;
+ }
+ /**
+ * 获取真实客户端IP
+ * @param serverHttpRequest
+ * @return
+ */
+ public static String getRealIpAddress(ServerHttpRequest serverHttpRequest) {
+ String ipAddress;
+ try {
+ // 1.根据常见的代理服务器转发的请求ip存放协议,从请求头获取原始请求ip。
+ ipAddress = serverHttpRequest.getHeaders().getFirst(HEADER_X_FORWARDED_FOR);
+ if (StringUtils.isEmpty(ipAddress) || UNKNOWN.equalsIgnoreCase(ipAddress)) {
+ ipAddress = serverHttpRequest.getHeaders().getFirst(HEADER_PROXY_CLIENT_IP);
+ }
+ if (StringUtils.isEmpty(ipAddress) || UNKNOWN.equalsIgnoreCase(ipAddress)) {
+ ipAddress = serverHttpRequest.getHeaders().getFirst(HEADER_WL_PROXY_CLIENT_IP);
+ }
+
+ // 2.如果没有转发的ip,则取当前通信的请求端的ip
+ if (StringUtils.isEmpty(ipAddress) || UNKNOWN.equalsIgnoreCase(ipAddress)) {
+ InetSocketAddress inetSocketAddress = serverHttpRequest.getRemoteAddress();
+ if(inetSocketAddress != null) {
+ ipAddress = inetSocketAddress.getAddress().getHostAddress();
+ }
+ }
+
+ // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
+ // "***.***.***.***"
+ if (ipAddress != null) {
+ ipAddress = ipAddress.split(SEPARATOR)[0].trim();
+ }
+ } catch (Exception e) {
+ log.error("解析请求IP失败", e);
+ ipAddress = "解析IP失败";
+ }
+ return ipAddress == null ? "解析IP失败" : ipAddress;
+ }
+
+
+}
diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/filter/GlobalCacheRequestFilter.java b/api-gateway/src/main/java/com/heyu/api/gateway/filter/GlobalCacheRequestFilter.java
new file mode 100644
index 0000000..30a2282
--- /dev/null
+++ b/api-gateway/src/main/java/com/heyu/api/gateway/filter/GlobalCacheRequestFilter.java
@@ -0,0 +1,39 @@
+package com.heyu.api.gateway.filter;
+
+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 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;
+ }
+
+}
diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/filter/LogMdcConfiguration.java b/api-gateway/src/main/java/com/heyu/api/gateway/filter/LogMdcConfiguration.java
new file mode 100644
index 0000000..1df5779
--- /dev/null
+++ b/api-gateway/src/main/java/com/heyu/api/gateway/filter/LogMdcConfiguration.java
@@ -0,0 +1,82 @@
+package com.heyu.api.gateway.filter;
+
+import com.heyu.api.gateway.util.Log4Constans;
+import lombok.extern.slf4j.Slf4j;
+import org.reactivestreams.Subscription;
+import org.slf4j.MDC;
+import org.springframework.context.annotation.Configuration;
+import reactor.core.CoreSubscriber;
+import reactor.core.publisher.Hooks;
+import reactor.core.publisher.Operators;
+import reactor.util.context.Context;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+
+/**
+ *
+ *
*日志上下文切换配置
+ * @author wulin
+ * @since 2023-08-07
+ */
+@Configuration
+@Slf4j
+public class LogMdcConfiguration {
+ public static String PRINT_LOG_ID = Log4Constans.TRACE_ID;
+ private int errHashcode;
+ @PostConstruct
+ public void contextOperatorHook() {
+ Hooks.onEachOperator(PRINT_LOG_ID, Operators.lift((r, c) ->{
+ return new MdcContextSubscriber(c);
+ }));
+ }
+ @PreDestroy
+ public void cleanupHook() {
+ Hooks.resetOnEachOperator(PRINT_LOG_ID);
+ }
+
+ class MdcContextSubscriber implements CoreSubscriber {
+ private CoreSubscriber coreSubscriber;
+ public MdcContextSubscriber(CoreSubscriber c){
+ coreSubscriber = c;
+ }
+
+ @Override
+ public void onComplete() {
+ coreSubscriber.onComplete();
+ //暂时去掉,让每次切换时更换,即onNext插入
+ //MDC.remove(PRINT_LOG_ID);
+ }
+
+ @Override
+ public void onError(Throwable throwable) {
+
+ if(errHashcode != throwable.hashCode()){
+ errHashcode = throwable.hashCode();
+ log.info("异常{}", throwable);
+ }
+ coreSubscriber.onError(throwable);
+ MDC.remove(PRINT_LOG_ID);
+
+ }
+
+ @Override
+ public void onSubscribe(Subscription subscription) {
+ coreSubscriber.onSubscribe(subscription);
+ }
+
+ @Override
+ public void onNext(T t) {
+ if(coreSubscriber.currentContext().hasKey(PRINT_LOG_ID)){
+ MDC.put(PRINT_LOG_ID, coreSubscriber.currentContext().get(PRINT_LOG_ID));
+ }
+ coreSubscriber.onNext(t);
+ }
+
+
+ @Override
+ public Context currentContext() {
+ return coreSubscriber.currentContext();
+ }
+ }
+}
diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/handler/GatewayExceptionHandler.java b/api-gateway/src/main/java/com/heyu/api/gateway/handler/GatewayExceptionHandler.java
new file mode 100644
index 0000000..df34c94
--- /dev/null
+++ b/api-gateway/src/main/java/com/heyu/api/gateway/handler/GatewayExceptionHandler.java
@@ -0,0 +1,49 @@
+package com.heyu.api.gateway.handler;
+
+import com.heyu.api.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 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 if (ex instanceof RuntimeException) {
+ msg = ex.getMessage();
+ } else {
+ msg = "内部服务器错误";
+ }
+
+ log.error("[网关异常处理]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), ex.getMessage());
+
+ return WebFluxUtils.webFluxResponseWriter(response, msg);
+ }
+
+}
diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/util/ApiConstants.java b/api-gateway/src/main/java/com/heyu/api/gateway/util/ApiConstants.java
new file mode 100644
index 0000000..a1a7ba8
--- /dev/null
+++ b/api-gateway/src/main/java/com/heyu/api/gateway/util/ApiConstants.java
@@ -0,0 +1,92 @@
+package com.heyu.api.gateway.util;
+
+public class ApiConstants {
+ public static final Integer Int_0 = new Integer(0);
+ public static final Integer Int_1 = new Integer(1);
+ public static final Integer Int_2 = new Integer(2);
+ public static final Integer Int_3 = new Integer(3);
+
+ /**
+ * 不需要 注解名称
+ */
+ public static final String NOT_INTERCEPT_ANNOTATION_NAME = "NotIntercept";
+ /**
+ * token相关的所有信息
+ */
+ public static final String TOKEN_INFO = "TOKEN_INFO$";
+
+ /**
+ * account 信息
+ */
+ public static final String ACCOUNT_INFO = "ACCOUNT_INFO$";
+
+ /**
+ * token 一分钟访问次数
+ */
+ public static final String TOKEN_MINUTES_VISIT_COUNT = "TOKEN_MINUTES_VISIT_COUNT$";
+
+ /**
+ * account账号一分钟访问次数
+ */
+ public static final String ACCOUNT_MINUTES_VISIT_COUNT = "ACCOUNT_MINUTES_VISIT_COUNT$";
+
+ /**
+ * update account amount lock
+ */
+ public static final String UPDATE_ACCOUNT_AMOUNT_LOCK = "UPDATE_ACCOUNT_AMOUNT_LOCK$";
+
+
+ public static String SYSTEM = "system";
+
+ public static String USER_NAME = "user_name";
+
+ public static String TOKEN = "token";
+
+
+
+ /**
+ * 任务调度参数key
+ */
+ public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY";
+
+
+ /**
+ * 定时任务状态
+ *
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年12月3日 上午12:07:22
+ */
+ public enum ScheduleStatus {
+ /**
+ * 正常
+ */
+ NORMAL(0),
+ /**
+ * 暂停
+ */
+ PAUSE(1);
+
+ private int value;
+
+ ScheduleStatus(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+ }
+
+
+
+
+ public static final String VERIFY_INTERFACE = "verifyInterface";
+
+ public static final String ECHOBACK = "echoback";
+ public static final String X_FORWARDED_PATH = "X-Forwarded-Path";
+
+ public static final String API_USER = "api-user";
+
+
+}
diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/util/Log4Constans.java b/api-gateway/src/main/java/com/heyu/api/gateway/util/Log4Constans.java
new file mode 100644
index 0000000..152f26e
--- /dev/null
+++ b/api-gateway/src/main/java/com/heyu/api/gateway/util/Log4Constans.java
@@ -0,0 +1,25 @@
+package com.heyu.api.gateway.util;
+
+public class Log4Constans {
+
+ /**
+ * traceId ,日志编号
+ */
+ public static String TRACE_ID = "logid";
+
+ /**
+ * ip 值
+ */
+ public static String IP = "request_ip";
+
+
+ /**
+ * 请求uri
+ */
+ public static String URI = "request_uri";
+
+ /**
+ * 耗时
+ */
+ public static String START_TIME = "start_time";
+}
diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/util/OrderUtils.java b/api-gateway/src/main/java/com/heyu/api/gateway/util/OrderUtils.java
new file mode 100644
index 0000000..1c9dcbb
--- /dev/null
+++ b/api-gateway/src/main/java/com/heyu/api/gateway/util/OrderUtils.java
@@ -0,0 +1,34 @@
+package com.heyu.api.gateway.util;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.text.SimpleDateFormat;
+
+
+/**
+ * 订单号生成工具
+ * 枚举相关信息,查看 https://www.showdoc.cc/web/#/page/495445295769339
+ */
+@Slf4j
+public class OrderUtils {
+
+ public static String getUserPoolOrder() {
+ SimpleDateFormat dateformat = new SimpleDateFormat("SSSyyyyMMddHHmmss");
+ StringBuffer sb = new StringBuffer();
+ return sb.
+ append((int) (Math.random() * 1000)).append(dateformat.format(System.currentTimeMillis())).toString();
+ }
+
+
+
+
+ public static String getOrderNo(String pre) {
+ SimpleDateFormat dateformat = new SimpleDateFormat("yyyyMMddHHmmssSSS");
+ StringBuffer sb = new StringBuffer(pre);
+ return sb.
+ append((int) (Math.random() * 1000)).append(dateformat.format(System.currentTimeMillis())).toString();
+ }
+
+
+
+}
diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/util/UserAuthContains.java b/api-gateway/src/main/java/com/heyu/api/gateway/util/UserAuthContains.java
new file mode 100644
index 0000000..5778fa6
--- /dev/null
+++ b/api-gateway/src/main/java/com/heyu/api/gateway/util/UserAuthContains.java
@@ -0,0 +1,16 @@
+package com.heyu.api.gateway.util;
+
+/**
+ * XXX
+ *
+ * @author weiyachao 包含
+ * @since 2023/9/20 16:25
+ */
+public interface UserAuthContains {
+
+ String API_TOKEN = "Api-Token";
+
+ String API_TYPE = "Api-Type";
+
+
+}
diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/util/WebFluxUtils.java b/api-gateway/src/main/java/com/heyu/api/gateway/util/WebFluxUtils.java
new file mode 100644
index 0000000..f7bd299
--- /dev/null
+++ b/api-gateway/src/main/java/com/heyu/api/gateway/util/WebFluxUtils.java
@@ -0,0 +1,88 @@
+package com.heyu.api.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 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 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 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 webFluxResponseWriter(ServerHttpResponse response, String contentType, HttpStatus status,
+ Object value, int code) {
+ response.setStatusCode(status);
+ response.getHeaders().add(HttpHeaders.CONTENT_TYPE, contentType);
+ HashMap map = new HashMap<>();
+ map.put("message", value.toString());
+ map.put("status", code);
+ map.put("code", "500");
+ map.put("timestamp", System.currentTimeMillis());
+ DataBuffer dataBuffer = response.bufferFactory().wrap(JSON.toJSONString(map).getBytes());
+ return response.writeWith(Mono.just(dataBuffer));
+ }
+}
diff --git a/api-gateway/src/main/resources/bootstrap-dev.yml b/api-gateway/src/main/resources/bootstrap-dev.yml
new file mode 100644
index 0000000..539ce7c
--- /dev/null
+++ b/api-gateway/src/main/resources/bootstrap-dev.yml
@@ -0,0 +1,84 @@
+spring:
+ cloud:
+ inetutils:
+ preferredNetworks:
+ - 192.168 #注册到nacos中心优先匹配的IP
+ gateway:
+ routes:
+ - id: heyu-api-user-api
+ uri: lb://heyu-api-user-api
+ predicates:
+ - Path=/api-user/**
+ filters:
+ # 转发时去掉一层路径
+ - StripPrefix=1
+ - id: heyu-api-websocket
+ uri: lb://heyu-api-websocket
+ predicates:
+ - Path=/api-websocket/**
+ filters:
+ # 转发时去掉一层路径
+ - StripPrefix=1
+ globalcors:
+ corsConfigurations:
+ '[/**]':
+ # 允许携带认证信息
+ allow-credentials: true
+ # 允许跨域的源(网站域名/ip),设置*为全部
+ allowedOriginPatterns: "*"
+ # 允许跨域的method, 默认为GET和OPTIONS,设置*为全部
+ allowedMethods: "*"
+ # 允许跨域请求里的head字段,设置*为全部
+ allowedHeaders: "*"
+ config:
+ # 如果本地配置优先级高,那么 override-none 设置为 true,包括系统环境变量、本地配置文件等配置
+ override-none: true
+ # 如果想要远程配置优先级高,那么 allow-override 设置为 false,如果想要本地配置优先级高那么 allow-override 设置为 true
+ allow-override: true
+ # 只有系统环境变量或者系统属性才能覆盖远程配置文件的配置,本地配置文件中配置优先级低于远程配置;注意本地配置文件不是系统属性
+ override-system-properties: false
+ nacos:
+ discovery:
+ # 服务注册地址
+ server-addr: nacos.iwulin.tech:30571
+ namespace: ${spring.profiles.active}
+ password: hz_HeYu@202518
+ config:
+ namespace: ${spring.profiles.active}
+ # 配置中心地址
+ server-addr: nacos.iwulin.tech:30571
+ password: hz_HeYu@202518
+ # 配置文件格式
+ file-extension: yml
+ # 共享配置
+ #shared-configs:
+ # - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
+ redis:
+ password: O^pv_3#slxQ
+ port: 32048
+ host: rrdd.iwulin.tech
+ timeout: 5000
+# 安全配置
+security:
+ # 防止XSS攻击
+ xss:
+ enabled: false
+ # 排除的路径
+ exclude-urls:
+ - /api-user/user/login/pwd
+ - /api-user/ip/api/getIp
+ - /api-websocket/push/message
+ - /api-websocket/websocket/box
+ - /api-websocket/websocket/customer
+ - /api-websocket/websocket/tts/token
+ - /api-websocket/websocket/init/sysTalkAnswer
+ # ip免登白名单
+ auth-ip: #127.0.0.1,192.168.8.141
+ #免登,免校验url
+ auth-urls:
+ - /actuator
+ - /websocket
+#application:
+# cors:
+# allowed-crigin-patterns:
+# - /api-user/user/user/login/pwd
diff --git a/api-gateway/src/main/resources/bootstrap-online.yml b/api-gateway/src/main/resources/bootstrap-online.yml
new file mode 100644
index 0000000..c508d58
--- /dev/null
+++ b/api-gateway/src/main/resources/bootstrap-online.yml
@@ -0,0 +1,18 @@
+spring:
+ cloud:
+ nacos:
+ discovery:
+ # 服务注册地址
+ server-addr: 127.0.0.1:8848
+ namespace: ${spring.profiles.active}
+ #password: hz_HeYu@202518
+ config:
+ # 配置中心地址
+ server-addr: 127.0.0.1:8848
+ namespace: ${spring.profiles.active}
+ #password: hz_HeYu@202518
+ # 配置文件格式
+ file-extension: yml
+ # 共享配置
+ #shared-configs:
+ # - application.${spring.cloud.nacos.config.file-extension}
diff --git a/api-gateway/src/main/resources/bootstrap.yml b/api-gateway/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..8c6b851
--- /dev/null
+++ b/api-gateway/src/main/resources/bootstrap.yml
@@ -0,0 +1,32 @@
+server:
+ port: 8080
+spring:
+ application:
+ name: heyu-api-gateway
+ profiles:
+ active: dev
+ main:
+ allow-bean-definition-overriding: true
+ allow-circular-references: true
+
+
+
+zuul:
+ ribbon:
+ eager-load:
+ enabled: true
+ clients: heyu-api-user-api
+ ignoredServices: '*'
+ host:
+ connect-timeout-millis: 10000
+ socket-timeout-millis: 10000
+ ratelimit:
+ key-prefix: pig-ratelimite
+ enabled: true
+ repository: REDIS
+ behind-proxy: true
+ policies:
+ sina-upms-service:
+ limit: 100
+ quota: 100
+ refresh-interval: 3
diff --git a/api-gateway/src/main/resources/logback-dev.xml b/api-gateway/src/main/resources/logback-dev.xml
new file mode 100644
index 0000000..1281941
--- /dev/null
+++ b/api-gateway/src/main/resources/logback-dev.xml
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+ ${log.pattern}
+ UTF-8
+
+
+
+
+
+ ${log.path}/all.log
+
+
+
+ ${log.path}/%d{yyyy-MM-dd}_all.log
+
+ 15
+
+
+ ${log.pattern}
+ UTF-8
+
+
+
+ INFO
+
+
+
+
+
+
+ ${log.path}/warn.log
+
+
+
+ ${log.path}/%d{yyyy-MM-dd}_wran.log
+
+ 15
+
+
+ ${log.pattern}
+ UTF-8
+
+
+
+ WARN
+
+
+
+
+ ${log.path}/error.log
+
+
+
+ ${log.path}/%d{yyyy-MM-dd}_error.log
+
+ 15
+
+
+ ${log.pattern}
+ UTF-8
+
+
+
+ ERROR
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api-gateway/src/main/resources/logback-prod.xml b/api-gateway/src/main/resources/logback-prod.xml
new file mode 100644
index 0000000..6f6fde7
--- /dev/null
+++ b/api-gateway/src/main/resources/logback-prod.xml
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+ ${log.pattern}
+ UTF-8
+
+
+
+
+
+ ${log.path}/all.log
+
+
+
+ ${log.path}/%d{yyyy-MM-dd}_all.log
+
+ 15
+
+
+ ${log.pattern}
+ UTF-8
+
+
+
+ INFO
+
+
+
+
+
+
+ ${log.path}/warn.log
+
+
+
+ ${log.path}/%d{yyyy-MM-dd}_wran.log
+
+ 15
+
+
+ ${log.pattern}
+ UTF-8
+
+
+
+ WARN
+
+
+
+
+ ${log.path}/error.log
+
+
+
+ ${log.path}/%d{yyyy-MM-dd}_error.log
+
+ 15
+
+
+ ${log.pattern}
+ UTF-8
+
+
+
+ ERROR
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api-gateway/src/main/resources/logback-test.xml b/api-gateway/src/main/resources/logback-test.xml
new file mode 100644
index 0000000..09ffc80
--- /dev/null
+++ b/api-gateway/src/main/resources/logback-test.xml
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+ ${log.pattern}
+ UTF-8
+
+
+
+
+
+ ${log.path}/all.log
+
+
+
+ ${log.path}/%d{yyyy-MM-dd}_all.log
+
+ 15
+
+
+ ${log.pattern}
+ UTF-8
+
+
+
+ INFO
+
+
+
+
+
+
+ ${log.path}/warn.log
+
+
+
+ ${log.path}/%d{yyyy-MM-dd}_wran.log
+
+ 15
+
+
+ ${log.pattern}
+ UTF-8
+
+
+
+ WARN
+
+
+
+
+ ${log.path}/error.log
+
+
+
+ ${log.path}/%d{yyyy-MM-dd}_error.log
+
+ 15
+
+
+ ${log.pattern}
+ UTF-8
+
+
+
+ ERROR
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 8d49f46..242d2e6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,6 +21,7 @@
api-mapper
api-third
api-web
+ api-gateway
0.0.1-SNAPSHOT
易借消息服务