业务是调用另一个平台API,用他们的接口能力实现一些功能。
真正请求前的filter,我把一些请求前的验证和日志入库放在了这里。
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson2.util.DateUtils; import com.iMagine.iMagine_common.exception.MyException; import com.iMagine.iMagine_common.result.CommonResult; import com.iMagine.iMagine_common.utils.UUIDUtil; import com.iMagine.iMagine_mapper.entity.User; import com.iMagine.iMagine_pro.constant.ErrorEnum; import com.iMagine.iMagine_pro.constant.SysConstant; import com.iMagine.iMagine_pro.feign.body.AiServerResponseBody; import com.iMagine.iMagine_pro.service.MjToAiService; import com.iMagine.iMagine_pro.utils.TokenUtil; import com.iMagine.iMagine_pro.utils.ZuulParameterUtil; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.util.HTTPRequestUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; import org.springframework.util.StreamUtils; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.nio.charset.Charset; import java.util.Date; import java.util.concurrent.ConcurrentHashMap; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream;/*** Zuul过滤器,必须继承ZuulFilter父类。* 当前类型的对象必须交由Spring容器管理。使用@Component注解描述。* 继承父类后,必须实现父类中定义的4个抽象方法。* shouldFilter、 run、 filterType、 filterOrder*/ @Component @Slf4j public class LoggerPostFilter extends ZuulFilter {@Autowiredprivate MjToAiService mjToAiService;/*** 返回boolean类型。代表当前filter是否生效。* 默认值为false。* 返回true代表开启filter。*/@Overridepublic boolean shouldFilter() {return true;}/*** run方法就是过滤器的具体逻辑。* return 可以返回任意的对象,当前实现忽略。(spring-cloud-zuul官方解释)* 直接返回null即可。*/@Overridepublic Object run() {log.info("LoggerPostFilter任务处理开始...");// 获取zuul提供的上下文对象RequestContext context = RequestContext.getCurrentContext();HttpServletRequest request = context.getRequest();String requestUrl = request.getRequestURI();log.info("requestUrl:{}",requestUrl);//创建统一UUIDString uuid = UUIDUtil.getUUID();ConcurrentHashMap<String,Object> params = new ConcurrentHashMap<>(4);HttpServletResponse response = context.getResponse();params.put("uuid",uuid);params.put("date",new Date());try {InputStream responseDataStream = context.getResponseDataStream();String contentEncoding = context.getZuulRequestHeaders().get("accept-encoding");if (responseDataStream != null && "gzip".equals(contentEncoding) && context.getResponseGZipped()) {responseDataStream = new GZIPInputStream(context.getResponseDataStream());}else{responseDataStream = context.getResponseDataStream();}String body = StreamUtils.copyToString(responseDataStream, Charset.forName("UTF-8"));//根据code值替换提示内容JSONObject requestJson = JSON.parseObject(body);log.info("requestJson:{}",requestJson);// 处理一些返回的数据到paramsparams.put("code",response.getStatus());params.put("returnMj",body);if(!ObjectUtils.isEmpty(response) && response.getStatus() == 200){//设置接口记录为执行中状态params.put("operationResult",SysConstant.STATUS_TWO);//收集一些埋点需要的参数handlerSomething(body,params);}else{//设置接口记录为失败状态params.put("operationResult",SysConstant.STATUS_ONE);//根据code替换返回前端的提示信息log.error("返回异常报文{}",JSON.toJSONString(requestJson));String code = "";if(ObjectUtils.isEmpty(requestJson)){code = String.valueOf(response.getStatus());requestJson = new JSONObject();requestJson.put("code",code);}else{code = requestJson.get("code").toString();}String reason = ErrorEnum.ErrorEnumType.getModelUploadType(code);if(StringUtils.isBlank(reason)) reason = ErrorEnum.ErrorEnumType.getModelUploadType("1000");requestJson.put("reason",reason);}//对请求的入参进行筛选记录log.info("开始调用handlerRequest...,{}",params);handlerRequest(context,params);response.setCharacterEncoding("UTF-8");response.setContentType("application/json");// 将修改后的内容重新压缩为 GZIP 格式if (responseDataStream != null && "gzip".equals(contentEncoding) && context.getResponseGZipped()) {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);gzipOutputStream.write(JSON.toJSONString(CommonResult.success(requestJson)).getBytes("UTF-8"));gzipOutputStream.close();// 设置新的压缩后的响应数据流context.setResponseDataStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));}else{// 设置新的压缩后的响应数据流context.setResponseBody(JSON.toJSONString(CommonResult.success(requestJson)));}} catch (Exception e) {log.error("请求异常!{}",e);// 异常数据记录User user = TokenUtil.getUserByToken();mjToAiService.handlerException(uuid,e,DateUtils.parseDate(params.get("date")+""),user,context.getRequest());throw new MyException("请求异常!");}log.info("LoggerPostFilter任务处理结束!");return null;}/*** 收集一些埋点需要的参数* @param body 接口返回的报文* @param params 需要存储的集合*/private void handlerSomething( String body,ConcurrentHashMap<String,Object> params){String paramString = body.replaceAll(" ", "").replaceAll(System.getProperty("line.separator"), "");JSONObject responseBody = JSON.parseObject(paramString);if (!ObjectUtils.isEmpty(responseBody)){log.info("【返回参数】{}" , responseBody);//不确定接口返回的是jobid 还是 id//如果是正常返回,则覆盖uuid,届时用来对回调接口做关联if (ObjectUtils.isEmpty(responseBody.get("id"))){params.put("uuid",responseBody.get("jobid"));}else{params.put("uuid",responseBody.get("id"));}}}/*** 对请求的入参进行筛选记录* 统一记录生图埋点数据* @param context*/private void handlerRequest(RequestContext context,ConcurrentHashMap<String,Object> params){//对MJ相关生图接口做埋点log.info("对MJ相关生图接口做埋点...");HttpServletRequest request = context.getRequest();String requestUrl = request.getRequestURI();Date dateHandler = DateUtils.parseDate(String.valueOf(params.get("date")));JSONObject requestMap = JSON.parseObject(JSON.toJSONString(ZuulParameterUtil.getRequestParams(context)));User user = TokenUtil.getUserByToken();try {log.info("接口url:{},参数列表:{}", requestUrl,requestMap);String clientIp = TokenUtil.getRequest().getRemoteHost();//1.请求悠船文生图接口//2.封装AiServerResponseBodyAiServerResponseBody result = mjToAiService.handlerSpecial(Integer.valueOf(params.get("code")+""),params.get("returnMj") + "",params.get("uuid")+"",dateHandler,user);log.info("AiServerResponseBody 存入数据{}",result);//3.异步插入调用记录img_ai_record,日活记录img_dau_record,异步处理mjToAiService.addRecord(params.get("returnMj") + "",Integer.valueOf(params.get("code")+""),JSON.toJSONString(requestMap),params.get("uuid")+"",dateHandler,request.getRequestURI(),params.get("operationResult")+"",user,clientIp,1);log.info("diffusion uuid:{}, result:{}", params.get("uuid")+"", result);} catch (Exception e) {//5.处理异常log.error("handlerRequest异常:{}",e);mjToAiService.handlerException(params.get("uuid")+"",e,dateHandler,user,request);}}/*** 过滤器的类型。可选值有:* pre - 前置过滤* route - 路由后过滤* error - 异常过滤* post - 远程服务调用后过滤*/@Overridepublic String filterType() {return "post";}/*** 同种类的过滤器的执行顺序。* 按照返回值的自然升序执行。*/@Overridepublic int filterOrder() {return 2;} }
请求回来拦截的filter,解析返回的报文,分析数据和业务处理,最终gzip重构返回报文。
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.util.DateUtils;
import com.iMagine.iMagine_common.exception.MyException;
import com.iMagine.iMagine_common.result.CommonResult;
import com.iMagine.iMagine_common.utils.UUIDUtil;
import com.iMagine.iMagine_mapper.entity.User;
import com.iMagine.iMagine_pro.constant.ErrorEnum;
import com.iMagine.iMagine_pro.constant.SysConstant;
import com.iMagine.iMagine_pro.feign.body.AiServerResponseBody;
import com.iMagine.iMagine_pro.service.MjToAiService;
import com.iMagine.iMagine_pro.utils.TokenUtil;
import com.iMagine.iMagine_pro.utils.ZuulParameterUtil;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.util.HTTPRequestUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StreamUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
/**
* Zuul过滤器,必须继承ZuulFilter父类。
* 当前类型的对象必须交由Spring容器管理。使用@Component注解描述。
* 继承父类后,必须实现父类中定义的4个抽象方法。
* shouldFilter、 run、 filterType、 filterOrder
*/
@Component
@Slf4j
public class LoggerPostFilter extends ZuulFilter {
@Autowired
private MjToAiService mjToAiService;
/**
* 返回boolean类型。代表当前filter是否生效。
* 默认值为false。
* 返回true代表开启filter。
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* run方法就是过滤器的具体逻辑。
* return 可以返回任意的对象,当前实现忽略。(spring-cloud-zuul官方解释)
* 直接返回null即可。
*/
@Override
public Object run() {
log.info("LoggerPostFilter任务处理开始...");
// 获取zuul提供的上下文对象
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
String requestUrl = request.getRequestURI();
log.info("requestUrl:{}",requestUrl);
//创建统一UUID
String uuid = UUIDUtil.getUUID();
ConcurrentHashMap<String,Object> params = new ConcurrentHashMap<>(4);
HttpServletResponse response = context.getResponse();
params.put("uuid",uuid);
params.put("date",new Date());
try {
InputStream responseDataStream = context.getResponseDataStream();
//这里的accept-encoding 看源码会自动转为小写
String contentEncoding = context.getZuulRequestHeaders().get("accept-encoding");
if (responseDataStream != null && "gzip".equals(contentEncoding) && context.getResponseGZipped()) {
responseDataStream = new GZIPInputStream(context.getResponseDataStream());
}else{
responseDataStream = context.getResponseDataStream();
}
String body = StreamUtils.copyToString(responseDataStream, Charset.forName("UTF-8"));
//根据code值替换提示内容
JSONObject requestJson = JSON.parseObject(body);
log.info("requestJson:{}",requestJson);
// 处理一些返回的数据到params
params.put("code",response.getStatus());
params.put("returnMj",body);
if(!ObjectUtils.isEmpty(response) && response.getStatus() == 200){
//设置接口记录为执行中状态
params.put("operationResult",SysConstant.STATUS_TWO);
//收集一些埋点需要的参数
handlerSomething(body,params);
}else{
//设置接口记录为失败状态
params.put("operationResult",SysConstant.STATUS_ONE);
//根据code替换返回前端的提示信息
log.error("返回异常报文{}",JSON.toJSONString(requestJson));
String code = "";
if(ObjectUtils.isEmpty(requestJson)){
code = String.valueOf(response.getStatus());
requestJson = new JSONObject();
requestJson.put("code",code);
}else{
code = requestJson.get("code").toString();
}
String reason = ErrorEnum.ErrorEnumType.getModelUploadType(code);
if(StringUtils.isBlank(reason)) reason = ErrorEnum.ErrorEnumType.getModelUploadType("1000");
requestJson.put("reason",reason);
}
//对请求的入参进行筛选记录
log.info("开始调用handlerRequest...,{}",params);
handlerRequest(context,params);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
// 将修改后的内容重新压缩为 GZIP 格式
if (responseDataStream != null && "gzip".equals(contentEncoding) && context.getResponseGZipped()) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);
gzipOutputStream.write(JSON.toJSONString(CommonResult.success(requestJson)).getBytes("UTF-8"));
gzipOutputStream.close();
// 设置新的压缩后的响应数据流
context.setResponseDataStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
}else{
// 设置新的压缩后的响应数据流
context.setResponseBody(JSON.toJSONString(CommonResult.success(requestJson)));
}
} catch (Exception e) {
log.error("请求异常!{}",e);
// 异常数据记录
User user = TokenUtil.getUserByToken();
mjToAiService.handlerException(uuid,e,DateUtils.parseDate(params.get("date")+""),user,context.getRequest());
throw new MyException("请求异常!");
}
log.info("LoggerPostFilter任务处理结束!");
return null;
}
/**
* 收集一些埋点需要的参数
* @param body 接口返回的报文
* @param params 需要存储的集合
*/
private void handlerSomething( String body,ConcurrentHashMap<String,Object> params){
String paramString = body.replaceAll(" ", "").replaceAll(System.getProperty("line.separator"), "");
JSONObject responseBody = JSON.parseObject(paramString);
if (!ObjectUtils.isEmpty(responseBody)){
log.info("【返回参数】{}" , responseBody);
//不确定接口返回的是jobid 还是 id
//如果是正常返回,则覆盖uuid,届时用来对回调接口做关联
if (ObjectUtils.isEmpty(responseBody.get("id"))){
params.put("uuid",responseBody.get("jobid"));
}else{
params.put("uuid",responseBody.get("id"));
}
}
}
/**
* 对请求的入参进行筛选记录
* 统一记录生图埋点数据
* @param context
*/
private void handlerRequest(RequestContext context,ConcurrentHashMap<String,Object> params){
//对MJ相关生图接口做埋点
log.info("对MJ相关生图接口做埋点...");
HttpServletRequest request = context.getRequest();
String requestUrl = request.getRequestURI();
Date dateHandler = DateUtils.parseDate(String.valueOf(params.get("date")));
JSONObject requestMap = JSON.parseObject(JSON.toJSONString(ZuulParameterUtil.getRequestParams(context)));
User user = TokenUtil.getUserByToken();
try {
log.info("接口url:{},参数列表:{}", requestUrl,requestMap);
String clientIp = TokenUtil.getRequest().getRemoteHost();
//1.请求悠船文生图接口
//2.封装AiServerResponseBody
AiServerResponseBody result = mjToAiService.handlerSpecial(
Integer.valueOf(params.get("code")+""),
params.get("returnMj") + "",
params.get("uuid")+"",
dateHandler,user);
log.info("AiServerResponseBody 存入数据{}",result);
//3.异步插入调用记录img_ai_record,日活记录img_dau_record,异步处理
mjToAiService.addRecord(params.get("returnMj") + "",Integer.valueOf(params.get("code")+""),
JSON.toJSONString(requestMap),params.get("uuid")+"",dateHandler,request.getRequestURI(),
params.get("operationResult")+"",user,clientIp,1);
log.info("diffusion uuid:{}, result:{}", params.get("uuid")+"", result);
} catch (Exception e) {
//5.处理异常
log.error("handlerRequest异常:{}",e);
mjToAiService.handlerException(params.get("uuid")+"",e,dateHandler,user,request);
}
}
/**
* 过滤器的类型。可选值有:
* pre - 前置过滤
* route - 路由后过滤
* error - 异常过滤
* post - 远程服务调用后过滤
*/
@Override
public String filterType() {
return "post";
}
/**
* 同种类的过滤器的执行顺序。
* 按照返回值的自然升序执行。
*/
@Override
public int filterOrder() {
return 2;
}
}