diff --git a/changelog.md b/changelog.md index cc58518b..b6ae81cf 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,10 @@ # changelog +## 4.3.0 + +- 升级`spring-boot/spring-cloud/spring-cloud-alibaba`版本 +- 修复`DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144`问题 + ## 4.2.7 - 修复两个微服务相同path问题 diff --git a/doc/docs/files/90100_常见问题.md b/doc/docs/files/90100_常见问题.md index f7879a1a..67e11668 100644 --- a/doc/docs/files/90100_常见问题.md +++ b/doc/docs/files/90100_常见问题.md @@ -1,5 +1,13 @@ # 常见问题 +## spring cloud gateway [DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144] + +如果POST请求body内容太大可能会报这个错误 + +- 解决版办法 + +网关指定配置`spring.codec.max-in-memory-size=xx`,xx默认是262144,即256K(262144=256*1024) + ## primordials is not defined node版本太高导致与gulp版本不兼容,解决方法:node退回11版本。参考https://blog.csdn.net/zxxzxx23/article/details/103000393 diff --git a/pom.xml b/pom.xml index 9242a9ce..342a50ce 100644 --- a/pom.xml +++ b/pom.xml @@ -2,13 +2,6 @@ - - org.springframework.boot - spring-boot-starter-parent - 2.1.8.RELEASE - - - 4.0.0 com.gitee.sop sop-parent @@ -30,7 +23,7 @@ - 4.2.7-SNAPSHOT + 4.3.0-SNAPSHOT 1.8 UTF-8 @@ -38,12 +31,12 @@ 1.8 - 2.1.8.RELEASE + 2.3.2.RELEASE - Greenwich.SR6 + Hoxton.SR8 - 2.1.2.RELEASE + 2.2.5.RELEASE @@ -73,11 +66,6 @@ - - io.projectreactor.netty - reactor-netty - 0.8.19.RELEASE - org.springframework.boot diff --git a/sop-common/sop-bridge-eureka/pom.xml b/sop-common/sop-bridge-eureka/pom.xml index 65881046..f619aa8b 100644 --- a/sop-common/sop-bridge-eureka/pom.xml +++ b/sop-common/sop-bridge-eureka/pom.xml @@ -4,11 +4,10 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> com.gitee.sop - sop-parent + sop-common ${revision} - ../../pom.xml + ../pom.xml - 4.0.0 sop-bridge-eureka diff --git a/sop-common/sop-bridge-nacos/pom.xml b/sop-common/sop-bridge-nacos/pom.xml index e30c9732..0b27ec6e 100644 --- a/sop-common/sop-bridge-nacos/pom.xml +++ b/sop-common/sop-bridge-nacos/pom.xml @@ -4,11 +4,10 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> com.gitee.sop - sop-parent + sop-common ${revision} - ../../pom.xml + ../pom.xml - 4.0.0 sop-bridge-nacos diff --git a/sop-common/sop-gateway-common/pom.xml b/sop-common/sop-gateway-common/pom.xml index 0fd8678f..8289bcf1 100644 --- a/sop-common/sop-gateway-common/pom.xml +++ b/sop-common/sop-gateway-common/pom.xml @@ -4,9 +4,9 @@ com.gitee.sop - sop-parent + sop-common ${revision} - ../../pom.xml + ../pom.xml 4.0.0 diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/config/SopGatewayEnvironmentPostProcessor.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/config/SopGatewayEnvironmentPostProcessor.java index 6f12412c..476f3083 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/config/SopGatewayEnvironmentPostProcessor.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/config/SopGatewayEnvironmentPostProcessor.java @@ -7,6 +7,7 @@ import org.springframework.core.env.PropertiesPropertySource; import org.springframework.core.env.PropertySource; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; +import org.springframework.util.unit.DataSize; import java.io.IOException; import java.util.Properties; @@ -31,9 +32,17 @@ public class SopGatewayEnvironmentPostProcessor implements EnvironmentPostProces } try { properties.load(resource.getInputStream()); + this.initMemSize(properties); return new PropertiesPropertySource(resource.getFilename(), properties); } catch (IOException ex) { throw new IllegalStateException("加载配置文件失败" + resource, ex); } } + + private void initMemSize(Properties properties) { + String size = properties.getProperty("spring.servlet.multipart.max-file-size", "10M"); + DataSize dataSize = DataSize.parse(size); + properties.putIfAbsent("spring.codec.max-in-memory-size", dataSize.toBytes()); + } + } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java index 49de630a..303650ae 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java @@ -16,13 +16,12 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; -import org.springframework.http.codec.HttpMessageReader; +import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.http.converter.FormHttpMessageConverter; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.util.MultiValueMap; import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.commons.CommonsMultipartResolver; -import org.springframework.web.reactive.function.server.HandlerStrategies; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilterChain; @@ -47,8 +46,6 @@ public class ServerWebExchangeUtil { private static final FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter(); - private static final List> messageReaders = HandlerStrategies.withDefaults().messageReaders(); - /** * 重定向 * @@ -70,10 +67,11 @@ public class ServerWebExchangeUtil { * 构建一个接受请求体的request * * @param exchange exchange + * @param codecConfigurer codecConfigurer * @return 返回ServerRequest */ - public static ServerRequest createReadBodyRequest(ServerWebExchange exchange) { - return ServerRequest.create(exchange, messageReaders); + public static ServerRequest createReadBodyRequest(ServerWebExchange exchange, ServerCodecConfigurer codecConfigurer) { + return ServerRequest.create(exchange, codecConfigurer.getReaders()); } public static String getRestfulPath(String path, String prefix) { diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/controller/ConfigChannelController.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/controller/ConfigChannelController.java index 1ccc64e1..47877065 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/controller/ConfigChannelController.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/controller/ConfigChannelController.java @@ -14,7 +14,9 @@ import com.gitee.sop.gatewaycommon.manager.RouteConfigManager; import com.gitee.sop.gatewaycommon.secret.IsvManager; import com.gitee.sop.gatewaycommon.util.RequestUtil; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.reactive.function.server.ServerRequest; @@ -45,9 +47,12 @@ public class ConfigChannelController { @Value("${sop.secret}") private String secret; + @Autowired + private ServerCodecConfigurer codecConfigurer; + @PostMapping("/sop/configChannelMsg") public Mono configChannel(ServerWebExchange exchange) { - ServerRequest serverRequest = ServerWebExchangeUtil.createReadBodyRequest(exchange); + ServerRequest serverRequest = ServerWebExchangeUtil.createReadBodyRequest(exchange, codecConfigurer); // 读取请求体中的内容 return serverRequest.bodyToMono(String.class) .flatMap(requestJson -> { diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/GatewayModifyResponseGatewayFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/GatewayModifyResponseGatewayFilter.java index 4d3bc4c1..ca45c1ac 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/GatewayModifyResponseGatewayFilter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/GatewayModifyResponseGatewayFilter.java @@ -5,36 +5,58 @@ import com.gitee.sop.gatewaycommon.bean.SopConstants; import com.gitee.sop.gatewaycommon.result.ResultExecutor; import org.apache.commons.lang3.StringUtils; import org.reactivestreams.Publisher; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter; import org.springframework.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage; +import org.springframework.cloud.gateway.filter.factory.rewrite.MessageBodyEncoder; import org.springframework.cloud.gateway.support.BodyInserterContext; -import org.springframework.cloud.gateway.support.DefaultClientResponse; import org.springframework.core.Ordered; import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseCookie; import org.springframework.http.client.reactive.ClientHttpResponse; +import org.springframework.http.codec.ServerCodecConfigurer; +import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpResponseDecorator; import org.springframework.util.MultiValueMap; import org.springframework.web.reactive.function.BodyInserter; import org.springframework.web.reactive.function.BodyInserters; -import org.springframework.web.reactive.function.client.ExchangeStrategies; +import org.springframework.web.reactive.function.client.ClientResponse; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; +import javax.annotation.PostConstruct; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static java.util.function.Function.identity; import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR; /** * 修改返回结果 + * * @author tanghc */ public class GatewayModifyResponseGatewayFilter implements GlobalFilter, Ordered { + @Autowired + private ServerCodecConfigurer codecConfigurer; + @Autowired + private Set bodyEncoders; + + private Map messageBodyEncoders; + @Override @SuppressWarnings("unchecked") public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { @@ -54,12 +76,14 @@ public class GatewayModifyResponseGatewayFilter implements GlobalFilter, Ordered } Class inClass = String.class; Class outClass = String.class; + HttpHeaders httpHeaders = new HttpHeaders(); - //explicitly add it in this way instead of 'httpHeaders.setContentType(originalResponseContentType)' - //this will prevent exception in case of using non-standard media types like "Content-Type: image" + // explicitly add it in this way instead of + // 'httpHeaders.setContentType(originalResponseContentType)' + // this will prevent exception in case of using non-standard media + // types like "Content-Type: image" httpHeaders.add(HttpHeaders.CONTENT_TYPE, originalResponseContentType); - ResponseAdapter responseAdapter = new ResponseAdapter(body, httpHeaders); - DefaultClientResponse clientResponse = new DefaultClientResponse(responseAdapter, ExchangeStrategies.withDefaults()); + ClientResponse clientResponse = prepareClientResponse(exchange, body, httpHeaders); //TODO: flux or mono Mono modifiedBody = clientResponse.bodyToMono(inClass) @@ -72,16 +96,21 @@ public class GatewayModifyResponseGatewayFilter implements GlobalFilter, Ordered return Mono.just(ret); }); - BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, outClass); - CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, exchange.getResponse().getHeaders()); + BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, + outClass); + CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, + exchange.getResponse().getHeaders()); return bodyInserter.insert(outputMessage, new BodyInserterContext()) .then(Mono.defer(() -> { - Flux messageBody = outputMessage.getBody(); + Mono messageBody = writeBody(getDelegate(), + outputMessage, outClass); HttpHeaders headers = getDelegate().getHeaders(); - if (!headers.containsKey(HttpHeaders.TRANSFER_ENCODING)) { - messageBody = messageBody.doOnNext(data -> headers.setContentLength(data.readableByteCount())); + if (!headers.containsKey(HttpHeaders.TRANSFER_ENCODING) + || headers.containsKey(HttpHeaders.CONTENT_LENGTH)) { + messageBody = messageBody.doOnNext(data -> headers + .setContentLength(data.readableByteCount())); } - //TODO: use isStreamingMediaType? + // TODO: fail if isStreamingMediaType? return getDelegate().writeWith(messageBody); })); } @@ -96,6 +125,42 @@ public class GatewayModifyResponseGatewayFilter implements GlobalFilter, Ordered return chain.filter(exchange.mutate().response(responseDecorator).build()); } + private ClientResponse prepareClientResponse( + ServerWebExchange exchange, + Publisher body, + HttpHeaders httpHeaders + ) { + ClientResponse.Builder builder; + builder = ClientResponse.create(exchange.getResponse().getStatusCode(), codecConfigurer.getReaders()); + return builder.headers(headers -> headers.putAll(httpHeaders)) + .body(Flux.from(body)).build(); + } + + private Mono writeBody(ServerHttpResponse httpResponse, + CachedBodyOutputMessage message, Class outClass) { + Mono response = DataBufferUtils.join(message.getBody()); + if (byte[].class.isAssignableFrom(outClass)) { + return response; + } + + List encodingHeaders = httpResponse.getHeaders() + .getOrEmpty(HttpHeaders.CONTENT_ENCODING); + for (String encoding : encodingHeaders) { + MessageBodyEncoder encoder = messageBodyEncoders.get(encoding); + if (encoder != null) { + DataBufferFactory dataBufferFactory = httpResponse.bufferFactory(); + response = response.publishOn(Schedulers.parallel()).map(buffer -> { + byte[] encodedResponse = encoder.encode(buffer); + DataBufferUtils.release(buffer); + return encodedResponse; + }).map(dataBufferFactory::wrap); + break; + } + } + + return response; + } + @Override public int getOrder() { return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1; @@ -140,4 +205,10 @@ public class GatewayModifyResponseGatewayFilter implements GlobalFilter, Ordered return null; } } + + @PostConstruct + public void after() { + this.messageBodyEncoders = bodyEncoders == null ? Collections.emptyMap() : bodyEncoders.stream() + .collect(Collectors.toMap(MessageBodyEncoder::encodingType, identity())); + } } \ No newline at end of file diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/IndexFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/IndexFilter.java index 0e15973a..0c261675 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/IndexFilter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/IndexFilter.java @@ -20,6 +20,7 @@ import org.springframework.core.annotation.Order; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; +import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpRequestDecorator; import org.springframework.web.reactive.function.BodyInserter; @@ -45,6 +46,9 @@ import java.util.Objects; @Order(Ordered.HIGHEST_PRECEDENCE) public class IndexFilter implements WebFilter { + @Autowired + private ServerCodecConfigurer codecConfigurer; + /** 路径白名单 */ private static final List PATH_WHITE_LIST = Arrays.asList( "/sop", "/actuator" @@ -78,7 +82,7 @@ public class IndexFilter implements WebFilter { } if (Objects.equals(path, indexPath) || "".equals(path)) { if (request.getMethod() == HttpMethod.POST) { - ServerRequest serverRequest = ServerWebExchangeUtil.createReadBodyRequest(exchange); + ServerRequest serverRequest = ServerWebExchangeUtil.createReadBodyRequest(exchange, codecConfigurer); // 读取请求体中的内容 Mono modifiedBody = serverRequest.bodyToMono(byte[].class) .switchIfEmpty(Mono.just("".getBytes())) diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/BaseExecutorAdapter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/BaseExecutorAdapter.java index 16af7f8d..76c68aec 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/BaseExecutorAdapter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/BaseExecutorAdapter.java @@ -93,7 +93,7 @@ public abstract class BaseExecutorAdapter implements ResultExecutor serviceResult = formatResult(serviceResult); boolean isMergeResult = this.isMergeResult(request); int responseStatus = this.getResponseStatus(request); -// this.doAfterRoute(serviceResult, responseStatus, request); + this.doAfterRoute(serviceResult, responseStatus, request); String finalResult; if (isMergeResult) { Map responseData = this.parseServiceResult(serviceResult, responseStatus, request); diff --git a/sop-common/sop-service-common/pom.xml b/sop-common/sop-service-common/pom.xml index 071288f5..6c1b3a37 100644 --- a/sop-common/sop-service-common/pom.xml +++ b/sop-common/sop-service-common/pom.xml @@ -5,9 +5,9 @@ com.gitee.sop - sop-parent + sop-common ${revision} - ../../pom.xml + ../pom.xml 4.0.0 diff --git a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/ServiceConfiguration.java b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/ServiceConfiguration.java index 1f302e88..460497da 100644 --- a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/ServiceConfiguration.java +++ b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/ServiceConfiguration.java @@ -1,6 +1,7 @@ package com.gitee.sop.servercommon.configuration; import com.alibaba.cloud.nacos.NacosDiscoveryProperties; +import com.alibaba.cloud.nacos.NacosServiceManager; import com.alibaba.cloud.nacos.discovery.NacosWatch; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.ObjectProvider; @@ -8,7 +9,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.core.env.Environment; -import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import java.util.Map; @@ -21,7 +22,12 @@ public class ServiceConfiguration extends SpringmvcConfiguration { @Bean @ConditionalOnMissingBean @ConditionalOnProperty("spring.cloud.nacos.discovery.server-addr") - public NacosWatch nacosWatch(NacosDiscoveryProperties nacosDiscoveryProperties, ObjectProvider taskScheduler, Environment environment) { + public NacosWatch nacosWatch( + NacosServiceManager nacosServiceManager, + NacosDiscoveryProperties nacosDiscoveryProperties, + ObjectProvider taskScheduler, + Environment environment + ) { Map metadata = nacosDiscoveryProperties.getMetadata(); String contextPath = environment.getProperty(METADATA_SERVER_CONTEXT_PATH); // 将context-path信息加入到metadata中 @@ -31,7 +37,7 @@ public class ServiceConfiguration extends SpringmvcConfiguration { // 在元数据中新增启动时间,不能修改这个值,不然网关拉取接口会有问题 // 如果没有这个值,网关会忽略这个服务 metadata.put("server.startup-time", String.valueOf(System.currentTimeMillis())); - return new NacosWatch(nacosDiscoveryProperties, taskScheduler); + return new NacosWatch(nacosServiceManager, nacosDiscoveryProperties, taskScheduler); } } diff --git a/sop-gateway/src/main/resources/META-INF/gateway.properties b/sop-gateway/src/main/resources/META-INF/gateway.properties index 652167d2..399730eb 100644 --- a/sop-gateway/src/main/resources/META-INF/gateway.properties +++ b/sop-gateway/src/main/resources/META-INF/gateway.properties @@ -34,6 +34,8 @@ spring.datasource.hikari.max-lifetime=500000 spring.cloud.gateway.discovery.locator.lower-case-service-id=true spring.cloud.gateway.discovery.locator.enabled=true +# \u54CD\u5E94\u8D85\u65F6\uFF0C\u9ED8\u8BA410\u79D2\uFF0810000\uFF09 +spring.cloud.gateway.httpclient.response-timeout=10000 # \u4E0D\u7528\u6539 mybatis.mapper-locations=classpath:mybatis/mapper/*.xml diff --git a/sop-gateway/src/main/resources/application-dev.properties b/sop-gateway/src/main/resources/application-dev.properties index 4a154c25..8afebce4 100644 --- a/sop-gateway/src/main/resources/application-dev.properties +++ b/sop-gateway/src/main/resources/application-dev.properties @@ -12,7 +12,7 @@ register.url=127.0.0.1:8848 # \u4E0A\u4F20\u6587\u4EF6\u6700\u5927\u5BB9\u91CF\uFF0C\u9ED8\u8BA410MB spring.servlet.multipart.max-file-size=10MB -# \u54CD\u5E94\u8D85\u65F6\uFF0C\u9ED8\u8BA45\u79D2\uFF085000\uFF09 -#spring.cloud.gateway.httpclient.response-timeout=5000 +# \u54CD\u5E94\u8D85\u65F6\uFF0C\u9ED8\u8BA410\u79D2\uFF0810000\uFF09 +#spring.cloud.gateway.httpclient.response-timeout=10000 logging.level.com.gitee=debug