diff --git a/README.md b/README.md
index 94844a3..c0604d7 100644
--- a/README.md
+++ b/README.md
@@ -76,11 +76,20 @@ API地址:http://demo.fizzgate.com/proxy/[服务名]/[API Path]
| v1.0.0 | v1.0.0 | v1.0.0 |
| v1.1.0 | v1.1.0 | v1.1.0 |
| v1.1.1 | v1.1.1 | v1.1.1 |
-| v1.2.0 | v1.2.0 | v1.1.1 |
+| v1.2.0 | v1.2.0 | v1.2.0 |
+
+从v1.3.0开始管理后台的前端和服务端合并成一个包
+
+- Fizz-gateway-community: 社区版
+
+- Fizz-manager-professional:管理后台
+
+| Fizz-gateway-community | Fizz-manager-professional |
+| ---------------------- | ------------------------- |
+| v1.3.0 | v1.3.0 |
请根据社区版的版本下载对应的管理后台版本
-
## 部署说明
[详细部署教程>>>](http://www.fizzgate.com/guide/installation/)
@@ -100,40 +109,22 @@ API地址:http://demo.fizzgate.com/proxy/[服务名]/[API Path]
#### 一、安装管理后台
-从github的releases(https://github.com/wehotel/fizz-gateway-community/releases) 下载 fizz-manager-professional 和 fizz-admin-professional 的安装包
+从github的releases(https://github.com/wehotel/fizz-gateway-community/releases) 下载 fizz-manager-professional 安装包
-##### 管理后台服务端(fizz-manager-professional)
+##### 管理后台(fizz-manager-professional)
-1. 首次安装执行`fizz-manager-professional-1.2.0-mysql.sql`数据库脚本
-2. 将`application-prod.yml`、`boot.sh`、`fizz-manager-professional-1.2.0.jar`拷贝到`/data/webapps/fizz-manager-professional`目录下
+说明:
+
+1. 以下安装步骤出现的`{version}`表示所使用管理后台的版本号,例如`1.3.0`。
+
+安装:
+
+1. 解压`fizz-manager-professional-{version}.zip`安装包
+2. 首次安装执行`fizz-manager-professional-{version}-mysql.sql`数据库脚本,从低版本升级至高版本选择执行update目录下对应升级脚本
3. 修改`application-prod.yml`文件,将相关配置修改成部署环境的配置
-4. 修改`boot.sh`文件,将`RUN_CMD`变量值修改成部署环境的JAVA实际路径
-5. 执行 `chmod +x boot.sh` 命令给`boot.sh`增加执行权限
-6. 执行 `./boot.sh start` 命令启动服务,支持 start/stop/restart/status命令
-7. 服务启动后访问前端登录地址,使用超级管理员账户`admin`密码`Aa123!`登录
-
-##### 管理后台前端(fizz-admin-professional)
-
-1.解压zip资源包,取文件夹【fizzAdmin】放置于服务器静态数据存放目录 如:/home/data/
-2.配置nginx服务器
-```
-server {
- listen 9000;
- server_name localhost:9000;
- location / {
- root /home/data/fizzAdmin;
- }
- location ^~ /api {
- rewrite ^/api/(.*) /$1 break;
- proxy_pass http://127.0.0.1:8000;
- }
-}
-# 注:root中地址需与资源包存放目录路径一致
-# 注:http://127.0.0.1:8000 为管理后台(fizz-manager-professional)的访问地址
-```
-3.访问地址
-【资源部署服务器IP + 端口号】如:http://127.0.0.1:9000/
-(端口号与nginx配置端口号一致)
+4. Linux启动 执行 `chmod +x boot.sh` 命令给`boot.sh`增加执行权限;执行 `./boot.sh start` 命令启动服务,支持 start/stop/restart/status命令
+5. Windows启动 执行`.\boot.cmd start` 命令启动服务,支持 start/stop/restart/status命令
+6. 服务启动后访问 http://{部署机器IP地址}:8000/#/login,使用超级管理员账户`admin`密码`Aa123!`登录
#### 二、安装fizz-gateway-community社区版
@@ -141,10 +132,11 @@ server {
1. 支持配置中心:apollo、nacos,支持注册中心:eureka、nacos,详细配置方法查看application.yml文件。
2. 如果使用apollo配置中心,可把application.yml文件内容迁到配置中心(apollo上应用名为:fizz-gateway);如果不使用apollo可去掉下面启动命令里的apollo参数。
+3. 以下安装步骤出现的`{version}`表示所使用网关的版本号,例如`1.3.0`。
安装方式一:脚本启动:
-1. 下载fizz-gateway-community的最新代码,修改application.yml配置文件里配置中心、注册中心、redis(redis配置需与管理后台一致)的配置,使用maven命令`mvn clean package -DskipTests=true`构建并把构建好的fizz-gateway-community-1.2.0.jar和boot.sh放同一目录
+1. 下载fizz-gateway-community的最新代码,修改application.yml配置文件里配置中心、注册中心、redis(redis配置需与管理后台一致)的配置,使用maven命令`mvn clean package -DskipTests=true`构建并把构建好的fizz-gateway-community-{version}.jar和boot.sh放同一目录
2. 修改boot.sh脚本的apollo连接,JVM内存配置
3. 执行 `./boot.sh start` 命令启动服务,支持 start/stop/restart/status命令
@@ -158,7 +150,7 @@ server {
1. 本地clone仓库上的最新代码,修改application.yml配置文件里配置中心、注册中心、redis(redis配置需与管理后台一致)的配置
2. 在项目根目录fizz-gateway-community下执行Maven命令`mvn clean package -DskipTests=true`打包
-3. 进入target目录,使用命令`java -jar -Denv=DEV -Dapollo.meta=http://localhost:66 fizz-gateway-community-1.2.0.jar`启动服务
+3. 进入target目录,使用命令`java -jar -Denv=DEV -Dapollo.meta=http://localhost:66 fizz-gateway-community-{version}.jar`启动服务
最后访问网关,地址形式为:http://127.0.0.1:8600/proxy/[服务名]/[API Path]
diff --git a/pom.xml b/pom.xml
index 691a288..6f2a81c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,12 +5,12 @@
org.springframework.boot
spring-boot-starter-parent
- 2.2.10.RELEASE
+ 2.2.12.RELEASE
we
fizz-gateway-community
- 1.2.0
+ 1.3.0
fizz-gateway-community
@@ -34,10 +34,13 @@
1.8
- 2.13.3
- 4.1.53.Final
- 4.5.13
+ 5.2.12.RELEASE
+ Dysprosium-SR15
+ 5.3.5.RELEASE
0.2.7
+ 4.1.56.Final
+ 4.4.14
+ 2.13.3
@@ -67,7 +70,7 @@
com.alibaba
fastjson
- 1.2.74
+ 1.2.75
@@ -116,7 +119,7 @@
org.apache.tapestry
tapestry-json
- 5.4.4
+ 5.4.5
@@ -128,7 +131,7 @@
org.codehaus.groovy
groovy-all
- 2.4.20
+ 2.4.21
@@ -146,13 +149,19 @@
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
- 2.2.5.RELEASE
+ 2.2.6.RELEASE
com.alibaba.boot
nacos-config-spring-boot-starter
${nacos.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-logging
+
+
com.alibaba.boot
@@ -166,7 +175,7 @@
org.springframework.boot
- spring-boot-starter-data-redis
+ spring-boot-starter-data-redis-reactive
diff --git a/sh/boot.sh b/sh/boot.sh
index 5e6eb48..0220472 100644
--- a/sh/boot.sh
+++ b/sh/boot.sh
@@ -1,21 +1,57 @@
#!/bin/bash
+cygwin=false
+darwin=false
+os400=false
+case "`uname`" in
+CYGWIN*) cygwin=true;;
+Darwin*) darwin=true;;
+OS400*) os400=true;;
+esac
+
+[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=$HOME/jdk/java
+[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/usr/java
+[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/usr/local/java
+[ ! -e "$JAVA_HOME/bin/java" ] && unset JAVA_HOME
+
+if [ -z "$JAVA_HOME" ]; then
+ if $darwin; then
+
+ if [ -x '/usr/libexec/java_home' ] ; then
+ export JAVA_HOME=`/usr/libexec/java_home`
+
+ elif [ -d "/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home" ]; then
+ export JAVA_HOME="/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home"
+ fi
+ else
+ JAVA_PATH=`dirname $(readlink -f $(which javac))`
+ if [ "x$JAVA_PATH" != "x" ]; then
+ export JAVA_HOME=`dirname $JAVA_PATH 2>/dev/null`
+ fi
+ fi
+ if [ -z "$JAVA_HOME" ]; then
+ echo "ERROR: Please set the JAVA_HOME variable in your environment!!!"
+ exit 1
+ fi
+fi
+
#进入脚本所在目录
cd `dirname $0`
#变量定义
APOLLO_META_SERVER=http://localhost:66
ENV=dev
-APP_NAME=fizz-gateway-community-1.2.0.jar
-APP_DEP_DIR=/data/webapps/fizz-gateway
-APP_LOG_DIR=/data/logs/fizz-gateway
-JAVA_CMD=/usr/local/java/bin/java
+APP_NAME=fizz-gateway-community-1.3.0.jar
+APP_DEP_DIR="` pwd`"
+APP_LOG_DIR=${APP_DEP_DIR}'/logs'
+JAVA_CMD=${JAVA_HOME}'/bin/java'
PID_FILE="${APP_LOG_DIR}/tpid"
CHECK_COUNT=3
-SERVER_IP="` ip a | egrep "brd" | grep inet | awk '{print $2}' | sed 's#/24##g'`"
-#创建应用目录
-mkdir -p ${APP_DEP_DIR}
+# 远程执行shell脚本初始化环境变量
+source '/etc/profile'
+
+SERVER_IP="` ip a |egrep "brd" |grep inet|awk '{print $2}'|sed 's#/24##g'|head -1`"
#创建日志目录
mkdir -p ${APP_LOG_DIR}
@@ -24,7 +60,7 @@ mkdir -p ${APP_LOG_DIR}
cd ${APP_DEP_DIR}
JAVA_OPTS="-Xms256m -Xmx4096m \
--XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m \
+-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m \
-XX:+AggressiveOpts \
-XX:+UseBiasedLocking \
-XX:+UseG1GC \
diff --git a/src/main/java/we/FizzGatewayApplication.java b/src/main/java/we/FizzGatewayApplication.java
index 0229a3e..2986fc8 100644
--- a/src/main/java/we/FizzGatewayApplication.java
+++ b/src/main/java/we/FizzGatewayApplication.java
@@ -1,13 +1,42 @@
+/*
+ * Copyright (C) 2020 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
package we;
import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration;
+import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import we.config.AggregateRedisConfig;
+import we.log.LogSendAppender;
+/**
+ * fizz gateway application boot entrance
+ *
+ * @author linwaiwai
+ * @author francis
+ * @author hongqiaowei
+ * @author zhongjie
+ */
@SpringBootApplication(
exclude = {ErrorWebFluxAutoConfiguration.class, RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class},
scanBasePackages = {"we"}
@@ -15,8 +44,30 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@NacosPropertySource(dataId = "${nacos.config.data-id}", groupId = "${nacos.config.group}", autoRefreshed = true)
@EnableDiscoveryClient
public class FizzGatewayApplication {
+ private static final Logger LOGGER = LoggerFactory.getLogger(FizzGatewayApplication.class);
public static void main(String[] args) {
- FizzAppContext.appContext = SpringApplication.run(FizzGatewayApplication.class, args);
+ SpringApplication springApplication = new SpringApplication(FizzGatewayApplication.class);
+ springApplication.setApplicationContextClass(CustomReactiveWebServerApplicationContext.class);
+ FizzAppContext.appContext = springApplication.run(args);
+ }
+
+ private static class CustomReactiveWebServerApplicationContext extends AnnotationConfigReactiveWebServerApplicationContext {
+ @Override
+ protected void onClose() {
+ super.onClose();
+ if (AggregateRedisConfig.proxyLettuceConnectionFactory != null) {
+ LOGGER.info("FizzGatewayApplication stopped.");
+ // set LogSendAppender.logEnabled to false to stop send log to fizz-manager
+ LogSendAppender.logEnabled = Boolean.FALSE;
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ // the ProxyLettuceConnectionFactory remove DisposableBean interface, so invoke destroy method here
+ AggregateRedisConfig.proxyLettuceConnectionFactory.destroy();
+ }
+ }
}
}
diff --git a/src/main/java/we/config/AggregateRedisConfig.java b/src/main/java/we/config/AggregateRedisConfig.java
new file mode 100644
index 0000000..3cf7831
--- /dev/null
+++ b/src/main/java/we/config/AggregateRedisConfig.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2020 the original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package we.config;
+
+import com.alibaba.nacos.api.config.annotation.NacosValue;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.dao.DataAccessException;
+import org.springframework.data.redis.connection.ReactiveRedisClusterConnection;
+import org.springframework.data.redis.connection.ReactiveRedisConnection;
+import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
+import org.springframework.data.redis.connection.RedisClusterConnection;
+import org.springframework.data.redis.connection.RedisConnection;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.connection.RedisSentinelConnection;
+import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
+import org.springframework.data.redis.listener.ReactiveRedisMessageListenerContainer;
+import we.log.LogSendAppender;
+import we.log.RedisLogSendServiceImpl;
+
+/**
+ * aggregate Redis config
+ *
+ * @author zhongjie
+ */
+@Configuration
+public class AggregateRedisConfig extends RedisReactiveConfig {
+ static final String AGGREGATE_REACTIVE_REDIS_PROPERTIES = "aggregateReactiveRedisProperties";
+ private static final String AGGREGATE_REACTIVE_REDIS_CONNECTION_FACTORY = "aggregateReactiveRedisConnectionFactory";
+ public static final String AGGREGATE_REACTIVE_REDIS_TEMPLATE = "aggregateReactiveRedisTemplate";
+ public static final String AGGREGATE_REACTIVE_REDIS_MESSAGE_LISTENER_CONTAINER = "aggregateReactiveRedisMessageListenerContainer";
+
+ private static final String SEND_LOG_TYPE_REDIS = "redis";
+ public static ProxyLettuceConnectionFactory proxyLettuceConnectionFactory;
+
+ @NacosValue(value = "${send-log.open:false}", autoRefreshed = true)
+ @Value("${send-log.open:false}")
+ private boolean sendLogOpen;
+
+ @NacosValue(value = "${send-log.channel:fizz_send_log_channel}", autoRefreshed = true)
+ @Value("${send-log.channel:fizz_log_channel}")
+ private String sendLogChannel;
+
+ @NacosValue(value = "${send-log.type:redis}", autoRefreshed = true)
+ @Value("${send-log.type:redis}")
+ private String sendLogType;
+
+ @ConfigurationProperties(prefix = "aggregate.redis")
+ @Configuration(AGGREGATE_REACTIVE_REDIS_PROPERTIES)
+ public static class AggregateRedisReactiveProperties extends RedisReactiveProperties {
+ }
+
+ public AggregateRedisConfig(@Qualifier(AGGREGATE_REACTIVE_REDIS_PROPERTIES) RedisReactiveProperties properties) {
+ super(properties);
+ }
+
+ @Override
+ @Bean(AGGREGATE_REACTIVE_REDIS_CONNECTION_FACTORY)
+ public ReactiveRedisConnectionFactory lettuceConnectionFactory() {
+ LettuceConnectionFactory lettuceConnectionFactory = (LettuceConnectionFactory) super.lettuceConnectionFactory();
+ if (SEND_LOG_TYPE_REDIS.equals(sendLogType)) {
+ proxyLettuceConnectionFactory = new ProxyLettuceConnectionFactory(lettuceConnectionFactory);
+ proxyLettuceConnectionFactory.afterPropertiesSet();
+ return proxyLettuceConnectionFactory;
+ } else {
+ return lettuceConnectionFactory;
+ }
+ }
+
+ @Override
+ @Bean(AGGREGATE_REACTIVE_REDIS_TEMPLATE)
+ public ReactiveStringRedisTemplate reactiveStringRedisTemplate(
+ @Qualifier(AGGREGATE_REACTIVE_REDIS_CONNECTION_FACTORY) ReactiveRedisConnectionFactory factory) {
+ ReactiveStringRedisTemplate reactiveStringRedisTemplate = super.reactiveStringRedisTemplate(factory);
+
+ // test redis can connect
+ reactiveStringRedisTemplate.getConnectionFactory().getReactiveConnection().ping().block();
+
+ if (SEND_LOG_TYPE_REDIS.equals(sendLogType)) {
+ // set LogSendAppender.logSendService here to let send log as early as possible
+ LogSendAppender.logSendService = new RedisLogSendServiceImpl(this, reactiveStringRedisTemplate);
+ }
+
+ return reactiveStringRedisTemplate;
+ }
+
+ @Bean(AGGREGATE_REACTIVE_REDIS_MESSAGE_LISTENER_CONTAINER)
+ public ReactiveRedisMessageListenerContainer aggregateReactiveRedisMessageListenerContainer(
+ @Qualifier(AGGREGATE_REACTIVE_REDIS_CONNECTION_FACTORY) ReactiveRedisConnectionFactory factory) {
+ return new ReactiveRedisMessageListenerContainer(factory);
+ }
+
+ public boolean getSendLogOpen() {
+ return sendLogOpen;
+ }
+
+ public String getSendLogChannel() {
+ return sendLogChannel;
+ }
+
+ public static class ProxyLettuceConnectionFactory implements RedisConnectionFactory, ReactiveRedisConnectionFactory {
+ ProxyLettuceConnectionFactory(LettuceConnectionFactory lettuceConnectionFactory) {
+ this.lettuceConnectionFactory = lettuceConnectionFactory;
+ }
+
+ private LettuceConnectionFactory lettuceConnectionFactory;
+
+ public void destroy() {
+ lettuceConnectionFactory.destroy();
+ }
+
+ void afterPropertiesSet() {
+ lettuceConnectionFactory.afterPropertiesSet();
+ }
+
+ @Override
+ public ReactiveRedisConnection getReactiveConnection() {
+ return lettuceConnectionFactory.getReactiveConnection();
+ }
+
+ @Override
+ public ReactiveRedisClusterConnection getReactiveClusterConnection() {
+ return lettuceConnectionFactory.getReactiveClusterConnection();
+ }
+
+ @Override
+ public RedisConnection getConnection() {
+ return lettuceConnectionFactory.getConnection();
+ }
+
+ @Override
+ public RedisClusterConnection getClusterConnection() {
+ return lettuceConnectionFactory.getClusterConnection();
+ }
+
+ @Override
+ public boolean getConvertPipelineAndTxResults() {
+ return lettuceConnectionFactory.getConvertPipelineAndTxResults();
+ }
+
+ @Override
+ public RedisSentinelConnection getSentinelConnection() {
+ return lettuceConnectionFactory.getSentinelConnection();
+ }
+
+ @Override
+ public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
+ return lettuceConnectionFactory.translateExceptionIfPossible(ex);
+ }
+ }
+}
diff --git a/src/main/java/we/constants/CommonConstants.java b/src/main/java/we/constants/CommonConstants.java
index 3174154..47ba0d2 100644
--- a/src/main/java/we/constants/CommonConstants.java
+++ b/src/main/java/we/constants/CommonConstants.java
@@ -33,6 +33,12 @@ public class CommonConstants {
public static final String HEADER_TRACE_ID = "X-TRACE-ID";
+ /**
+ * Prefix of traceId
+ */
+ public static final String TRACE_ID_PREFIX = "fizz-";
+
+
/**
* WildCard for PathMapping
*/
diff --git a/src/main/java/we/filter/FilterExceptionHandlerConfig.java b/src/main/java/we/filter/FilterExceptionHandlerConfig.java
index ac8eea1..a714090 100644
--- a/src/main/java/we/filter/FilterExceptionHandlerConfig.java
+++ b/src/main/java/we/filter/FilterExceptionHandlerConfig.java
@@ -55,8 +55,8 @@ public class FilterExceptionHandlerConfig {
return resp.writeWith(Mono.just(resp.bufferFactory().wrap(ex.getData().toString().getBytes())));
}
}
- if (t instanceof RedirectException) {
- RedirectException ex = (RedirectException) t;
+ if (t instanceof RedirectException) {
+ RedirectException ex = (RedirectException) t;
if (ex.getRedirectUrl() != null) {
ServerHttpResponse resp = exchange.getResponse();
resp.setStatusCode(HttpStatus.MOVED_PERMANENTLY);
@@ -64,23 +64,22 @@ public class FilterExceptionHandlerConfig {
return Mono.empty();
}
}
- if (t instanceof ExecuteScriptException) {
- ExecuteScriptException ex = (ExecuteScriptException) t;
- ServerHttpResponse resp = exchange.getResponse();
- resp.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
-
- RespEntity rs = null;
- String reqId = exchange.getRequest().getId();
- if (ex.getStepContext() != null && ex.getStepContext().returnContext()) {
- rs = new RespEntity(HttpStatus.INTERNAL_SERVER_ERROR.value(), t.getMessage(), reqId, ex.getStepContext());
- return resp.writeWith(Mono.just(resp.bufferFactory().wrap(JacksonUtils.writeValueAsString(rs).getBytes())));
- }else {
- rs = new RespEntity(HttpStatus.INTERNAL_SERVER_ERROR.value(), t.getMessage(), reqId);
- return resp.writeWith(Mono.just(resp.bufferFactory().wrap(rs.toString().getBytes())));
+ if (t instanceof ExecuteScriptException) {
+ ExecuteScriptException ex = (ExecuteScriptException) t;
+ ServerHttpResponse resp = exchange.getResponse();
+ resp.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
+ RespEntity rs = null;
+ String reqId = exchange.getRequest().getId();
+ if (ex.getStepContext() != null && ex.getStepContext().returnContext()) {
+ rs = new RespEntity(HttpStatus.INTERNAL_SERVER_ERROR.value(), t.getMessage(), reqId, ex.getStepContext());
+ return resp.writeWith(Mono.just(resp.bufferFactory().wrap(JacksonUtils.writeValueAsString(rs).getBytes())));
+ } else {
+ rs = new RespEntity(HttpStatus.INTERNAL_SERVER_ERROR.value(), t.getMessage(), reqId);
+ return resp.writeWith(Mono.just(resp.bufferFactory().wrap(rs.toString().getBytes())));
}
}
- Mono vm = WebUtils.responseError(exchange, filterExceptionHandler, HttpStatus.INTERNAL_SERVER_ERROR.value(), t.getMessage(), t);
- return vm;
+ Mono vm = WebUtils.responseError(exchange, filterExceptionHandler, HttpStatus.INTERNAL_SERVER_ERROR.value(), t.getMessage(), t);
+ return vm;
}
}
diff --git a/src/main/java/we/filter/FizzGatewayFilter.java b/src/main/java/we/filter/FizzGatewayFilter.java
index ae72814..02ae3c3 100644
--- a/src/main/java/we/filter/FizzGatewayFilter.java
+++ b/src/main/java/we/filter/FizzGatewayFilter.java
@@ -19,17 +19,22 @@ package we.filter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
+import com.alibaba.nacos.api.config.annotation.NacosValue;
+import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
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.stereotype.Component;
@@ -50,6 +55,7 @@ import we.fizz.ConfigLoader;
import we.fizz.Pipeline;
import we.fizz.input.Input;
import we.flume.clients.log4j2appender.LogService;
+import we.plugin.auth.ApiConfig;
import we.util.Constants;
import we.util.MapUtil;
import we.util.WebUtils;
@@ -64,25 +70,35 @@ public class FizzGatewayFilter implements WebFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(FizzGatewayFilter.class);
private static final DataBuffer emptyBody = new NettyDataBufferFactory(new UnpooledByteBufAllocator(false, true)).wrap(Constants.Symbol.EMPTY.getBytes());
-
+
@Resource
private ConfigLoader configLoader;
-
+
+ @NacosValue(value = "${need-auth:false}", autoRefreshed = true)
+ @Value("${need-auth:false}")
+ private boolean needAuth;
+
@Override
public Mono filter(ServerWebExchange exchange, WebFilterChain chain) {
+
+ String serviceId = WebUtils.getBackendService(exchange);
+ if ( serviceId == null || (ApiConfig.Type.SERVICE_ARRANGE != WebUtils.getApiConfigType(exchange) && needAuth) ) {
+ return chain.filter(exchange);
+ }
+
long start = System.currentTimeMillis();
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse serverHttpResponse = exchange.getResponse();
-
- if (WebUtils.getServiceId(exchange) == null) {
- return chain.filter(exchange);
- }
-
- String path = WebUtils.getPathPrefix(exchange) + WebUtils.getServiceId(exchange) + WebUtils.getReqPath(exchange);
+
+ String path = WebUtils.getClientReqPathPrefix(exchange) + serviceId + WebUtils.getBackendPath(exchange);
String method = request.getMethodValue();
AggregateResource aggregateResource = configLoader.matchAggregateResource(method, path);
if (aggregateResource == null) {
- return chain.filter(exchange);
+ if (WebUtils.getApiConfigType(exchange) == ApiConfig.Type.SERVICE_ARRANGE) {
+ return WebUtils.responseError(exchange, HttpStatus.INTERNAL_SERVER_ERROR.value(), "no aggregate resource: " + path);
+ } else {
+ return chain.filter(exchange);
+ }
}
Pipeline pipeline = aggregateResource.getPipeline();
@@ -93,11 +109,16 @@ public class FizzGatewayFilter implements WebFilter {
if(fizzHeaders != null && !fizzHeaders.isEmpty()) {
headers.putAll(fizzHeaders);
}
-
+
// traceId
- String traceId = exchange.getRequest().getId();
+ String tmpTraceId = CommonConstants.TRACE_ID_PREFIX + exchange.getRequest().getId();
+ if (StringUtils.isNotBlank(request.getHeaders().getFirst(CommonConstants.HEADER_TRACE_ID))) {
+ tmpTraceId = request.getHeaders().getFirst(CommonConstants.HEADER_TRACE_ID);
+ }
+ final String traceId = tmpTraceId;
LogService.setBizId(traceId);
- serverHttpResponse.getHeaders().add(CommonConstants.HEADER_TRACE_ID, traceId);
+
+ LOGGER.debug("matched aggregation api: {}", path);
// 客户端提交上来的信息
Map clientInput = new HashMap<>();
@@ -105,8 +126,8 @@ public class FizzGatewayFilter implements WebFilter {
clientInput.put("method", method);
clientInput.put("headers", headers);
clientInput.put("params", MapUtil.toHashMap(request.getQueryParams()));
-
-
+
+
Mono result = null;
if (HttpMethod.POST.name().equalsIgnoreCase(method)) {
result = DataBufferUtils.join(request.getBody()).defaultIfEmpty(emptyBody).flatMap(buf -> {
@@ -125,6 +146,7 @@ public class FizzGatewayFilter implements WebFilter {
return result.subscribeOn(Schedulers.elastic()).flatMap(aggResult -> {
LogService.setBizId(traceId);
String jsonString = JSON.toJSONString(aggResult.getBody());
+ LOGGER.debug("response body: {}", jsonString);
if (aggResult.getHeaders() != null && !aggResult.getHeaders().isEmpty()) {
aggResult.getHeaders().remove("Content-Length");
serverHttpResponse.getHeaders().addAll(aggResult.getHeaders());
@@ -133,7 +155,11 @@ public class FizzGatewayFilter implements WebFilter {
// defalut content-type
serverHttpResponse.getHeaders().add("Content-Type", "application/json; charset=UTF-8");
}
-
+ List headerTraceIds = serverHttpResponse.getHeaders().get(CommonConstants.HEADER_TRACE_ID);
+ if (headerTraceIds == null || !headerTraceIds.contains(traceId)) {
+ serverHttpResponse.getHeaders().add(CommonConstants.HEADER_TRACE_ID, traceId);
+ }
+
long end = System.currentTimeMillis();
pipeline.getStepContext().addElapsedTime("总耗时", end - start);
LOGGER.info("ElapsedTimes={}", JSON.toJSONString(pipeline.getStepContext().getElapsedTimes()));
diff --git a/src/main/java/we/filter/PreFilter.java b/src/main/java/we/filter/PreFilter.java
index 7d7dcc1..2c163cb 100644
--- a/src/main/java/we/filter/PreFilter.java
+++ b/src/main/java/we/filter/PreFilter.java
@@ -92,6 +92,7 @@ public class PreFilter extends ProxyAggrFilter {
Mono m;
if (authRes instanceof ApiConfig) {
ApiConfig ac = (ApiConfig) authRes;
+ afterAuth(exchange, ac);
m = executeFixedPluginFilters(exchange);
m = m.defaultIfEmpty(ReactorUtils.NULL);
if (ac.pluginConfigs == null || ac.pluginConfigs.isEmpty()) {
@@ -101,6 +102,7 @@ public class PreFilter extends ProxyAggrFilter {
.defaultIfEmpty(ReactorUtils.NULL).flatMap(func(exchange, chain));
}
} else if (authRes == ApiConfigService.Access.YES) {
+ afterAuth(exchange, null);
m = executeFixedPluginFilters(exchange);
return m.defaultIfEmpty(ReactorUtils.NULL).flatMap(func(exchange, chain));
} else {
@@ -111,6 +113,19 @@ public class PreFilter extends ProxyAggrFilter {
);
}
+ private void afterAuth(ServerWebExchange exchange, ApiConfig ac) {
+ String bs, bp;
+ if (ac == null) {
+ bs = WebUtils.getClientService(exchange);
+ bp = WebUtils.getClientReqPath(exchange);
+ } else {
+ bs = ac.backendService;
+ bp = ac.transform(WebUtils.getClientReqPath(exchange));
+ }
+ WebUtils.setBackendService(exchange, bs);
+ WebUtils.setBackendPath(exchange, bp);
+ }
+
private Mono chain(ServerWebExchange exchange, Mono m, PluginFilter pf) {
return m.defaultIfEmpty(ReactorUtils.NULL).flatMap(
v -> {
diff --git a/src/main/java/we/filter/ProxyAggrFilter.java b/src/main/java/we/filter/ProxyAggrFilter.java
index 99529ca..03c061a 100644
--- a/src/main/java/we/filter/ProxyAggrFilter.java
+++ b/src/main/java/we/filter/ProxyAggrFilter.java
@@ -32,7 +32,7 @@ public abstract class ProxyAggrFilter implements WebFilter {
@Override
public Mono filter(ServerWebExchange exchange, WebFilterChain chain) {
- String serviceId = WebUtils.getServiceId(exchange);
+ String serviceId = WebUtils.getClientService(exchange);
if (serviceId == null) {
return chain.filter(exchange);
} else {
diff --git a/src/main/java/we/filter/RouteFilter.java b/src/main/java/we/filter/RouteFilter.java
index 1c8581f..06471f5 100644
--- a/src/main/java/we/filter/RouteFilter.java
+++ b/src/main/java/we/filter/RouteFilter.java
@@ -34,8 +34,8 @@ import reactor.core.publisher.Mono;
import we.flume.clients.log4j2appender.LogService;
import we.legacy.RespEntity;
import we.plugin.auth.ApiConfig;
-import we.plugin.auth.AuthPluginFilter;
import we.proxy.FizzWebClient;
+import we.util.Constants;
import we.util.ThreadContext;
import we.util.WebUtils;
@@ -104,26 +104,26 @@ public class RouteFilter extends ProxyAggrFilter {
);
}
- ApiConfig ac = null;
- Object authRes = WebUtils.getFilterResultDataItem(exchange, AuthPluginFilter.AUTH_PLUGIN_FILTER, AuthPluginFilter.RESULT);
- if (authRes instanceof ApiConfig) {
- ac = (ApiConfig) authRes;
- }
+ String rid = clientReq.getId();
+ ApiConfig ac = WebUtils.getApiConfig(exchange);
+ if (ac == null) {
+ String pathQuery = WebUtils.getClientReqPathQuery(exchange);
+ return send(exchange, WebUtils.getClientService(exchange), pathQuery, hdrs);
+
+ } else if (ac.type == ApiConfig.Type.SERVICE_DISCOVERY) {
+ String pathQuery = WebUtils.appendQuery(WebUtils.getBackendPath(exchange), exchange);
+ return send(exchange, WebUtils.getBackendService(exchange), pathQuery, hdrs);
+
+ } else if (ac.type == ApiConfig.Type.REVERSE_PROXY) {
+ String uri = ac.getNextHttpHostPort() + WebUtils.appendQuery(WebUtils.getBackendPath(exchange), exchange);
+ return fizzWebClient.send(rid, clientReq.getMethod(), uri, hdrs, clientReq.getBody()).flatMap(genServerResponse(exchange));
- String relativeUri = WebUtils.getRelativeUri(exchange);
- if (ac == null || ac.proxyMode == ApiConfig.DIRECT_PROXY_MODE) {
- return send(exchange, WebUtils.getServiceId(exchange), relativeUri, hdrs);
} else {
- String realUri;
- String backendUrl = ac.getNextBackendUrl();
- int acpLen = ac.path.length();
- if (acpLen == 1) {
- realUri = backendUrl + relativeUri;
- } else {
- realUri = backendUrl + relativeUri.substring(acpLen);
- }
- relativeUri.substring(acpLen);
- return fizzWebClient.send(clientReq.getId(), clientReq.getMethod(), realUri, hdrs, clientReq.getBody()).flatMap(genServerResponse(exchange));
+ String err = "cant handle api config type " + ac.type;
+ StringBuilder b = ThreadContext.getStringBuilder();
+ WebUtils.request2stringBuilder(exchange, b);
+ log.error(b.append(Constants.Symbol.LF).append(err).toString(), LogService.BIZ_ID, rid);
+ return WebUtils.buildJsonDirectResponseAndBindContext(exchange, HttpStatus.OK, null, RespEntity.toJson(HttpStatus.INTERNAL_SERVER_ERROR.value(), err, rid));
}
}
diff --git a/src/main/java/we/fizz/ConfigLoader.java b/src/main/java/we/fizz/ConfigLoader.java
index 81254a9..db67f7c 100644
--- a/src/main/java/we/fizz/ConfigLoader.java
+++ b/src/main/java/we/fizz/ConfigLoader.java
@@ -21,6 +21,7 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.nacos.api.config.annotation.NacosValue;
+
import we.config.AppConfigProperties;
import we.fizz.input.ClientInputConfig;
import we.fizz.input.Input;
@@ -28,15 +29,18 @@ import we.fizz.input.InputType;
import org.apache.commons.io.FileUtils;
import org.noear.snack.ONode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
+import javax.annotation.PostConstruct;
import javax.annotation.Resource;
-import static we.listener.AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE;
+import static we.config.AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE;
import static we.util.Constants.Symbol.FORWARD_SLASH;
import java.io.File;
@@ -48,6 +52,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
+
/**
*
* @author francis
@@ -56,17 +61,21 @@ import java.util.concurrent.ConcurrentHashMap;
*/
@Component
public class ConfigLoader {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ConfigLoader.class);
+
/**
* 聚合配置存放Hash的Key
*/
private static final String AGGREGATE_HASH_KEY = "fizz_aggregate_config";
-
+
private static Map aggregateResources = null;
private static Map resourceKey2ConfigInfoMap = null;
private static Map aggregateId2ResourceKeyMap = null;
-
+
@Resource
private AppConfigProperties appConfigProperties;
+
@Resource(name = AGGREGATE_REACTIVE_REDIS_TEMPLATE)
private ReactiveStringRedisTemplate reactiveStringRedisTemplate;
@@ -85,11 +94,11 @@ public class ConfigLoader {
clientInputConfig.setHeaders(cfgNode.select("$.headers").toObject(Map.class));
clientInputConfig.setMethod(cfgNode.select("$.method").getString());
clientInputConfig.setPath(cfgNode.select("$.path").getString());
- if(clientInputConfig.getPath().startsWith(TEST_PATH_PREFIX)) {
+ if (clientInputConfig.getPath().startsWith(TEST_PATH_PREFIX)) {
// always enable debug for testing
clientInputConfig.setDebug(true);
- }else {
- if(cfgNode.select("$.debug") != null) {
+ } else {
+ if (cfgNode.select("$.debug") != null) {
clientInputConfig.setDebug(cfgNode.select("$.debug").getBoolean());
}
}
@@ -112,7 +121,7 @@ public class ConfigLoader {
for (Map stepConfig : stepConfigs) {
// set the specified env URL
this.handleRequestURL(stepConfig);
-
+
Step step = new Step.Builder().read(stepConfig);
step.setName((String) stepConfig.get("name"));
if (stepConfig.get("stop") != null) {
@@ -152,22 +161,23 @@ public class ConfigLoader {
}
return aggregateResources.get(resourceKey);
}
-
+
private void handleRequestURL(Map stepConfig) {
List