首页 > 其他分享 >zuul 验证,重写返回报文,解析gzip压缩response,使用案例

zuul 验证,重写返回报文,解析gzip压缩response,使用案例

时间:2024-11-12 17:56:49浏览次数:1  
标签:zuul get params context iMagine gzip import com response

业务是调用另一个平台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 {

    @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();
            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;
    }
}

请求回来拦截的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;
}
}

  

 

标签:zuul,get,params,context,iMagine,gzip,import,com,response
From: https://www.cnblogs.com/isyysblog/p/18542388

相关文章

  • Windows 11 对于 BZip2、Gzip、XZ 和 Zstandard 这些压缩格式的支持情况如下表所示:Win
      BZip2、Gzip、XZ和Zstandard(Zstd)是四种常见的压缩算法,它们在不同的应用场景中有各自的优势。下面是它们的详细说明:1. BZip2 (Block-sortingcompressionalgorithm)格式扩展名:.bz2压缩算法原理:BZip2使用Burrows-WheelerTransform(BWT)和Move-to-Front......
  • cn.hutool.http.HttpResponse 实现http请求
    前提引入hutool依赖具体实现//发送GET请求publicstaticHttpResponsesendGetRequest(Stringurl,Map<String,List<String>>httpHeaders){HttpResponseresponse=HttpRequest.get(url).header(httpHeaders).ex......
  • 编译openresty提示缺少gzip
    报错./configure:error:theHTTPgzipmodulerequiresthezliblibrary.Youcaneitherdisablethemodulebyusing--without-http_gzip_moduleoption,orinstallthezliblibraryintothesystem,orbuildthezliblibrarystaticallyfromthesourcewit......
  • Java面试系列-SpringCloud面试题20道,服务注册与发现,断路器,智能路由,熔断,追踪,网关,调用,限
    文章目录1.SpringCloud是什么?2.SpringCloud中的服务注册与发现是如何工作的?3.SpringCloud中的配置管理是如何工作的?4.SpringCloud中的断路器(Hystrix)是如何工作的?5.SpringCloud中的智能路由(Zuul)是如何工作的?6.SpringCloud中的服务熔断(Resilience4j)......
  • 终极对决!Tomcat 服务器压缩性能哪家强?Gzip、Brotli、Zstd 全面测评
    Tomcat服务器的三种压缩测评!!!三万字长文,现在这同样的文章在csdn不多了,家人们点点赞!!!欢迎订阅专栏,永不收费,hacker精神,更快获得第一手优质博文!!!Tomcat服务器三种压缩方式测评:Gzip、Brotli、Zstd在Web服务领域,数据压缩对于提升网站性能至关重要。通过压缩服务器响应......
  • 主动写入流对@ResponseBody注解的影响
    作者:京东零售柯贤铭问题回溯2023年Q2某日运营反馈一个问题,商品系统商家中心某批量工具模板无法下载,导致功能无法使用(因为模板是动态变化的)商家中心报错(JSON串):{"code":-1,"msg":"失败"} 负责的同事看到失败后立即与我展开讨论(因为不是关键业务,所以不需要回滚,修复即可),我们发......
  • [Nginx] 开启 gzip
    如果资源已经被压缩成Gzip格式了,Nginx不需要再次压缩。只需确保Nginx的配置正确指向这些Gzip文件,并使用gzip_static指令。如果资源不是Gzip格式,就需要全配置一下。http{ ## #GzipSettings ## gzipon;#启用gzip压缩 gzip_min_len......
  • DFIR(Digital Forensics and Incident Response,数字取证与事件响应)脚本是用于帮助分析
    DFIR(DigitalForensicsandIncidentResponse,数字取证与事件响应)脚本是用于帮助分析、调查和响应安全事件的自动化工具或脚本。这些脚本通常用于收集和分析系统、网络或应用程序中的数据,以识别潜在的安全威胁或漏洞。主要功能数据收集:自动化收集系统日志、网络流量、文件系......
  • 微服务网关Zuul
    一、Zuul简介Zuul是Netflix开源的微服务网关,包含对请求的路由和过滤两个主要功能。1)路由功能:负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础。2)过滤功能:负责对请求的过程进行干预,可以实现请求校验、服务聚合等功能。二、Zuul代码实现1)在pom.xml中......
  • Error response from daemon: Get “https://registry-1.docker.io/v2/“: net/http:
    目录1问题2解决办法3后记1问题Errorresponsefromdaemon:Get“https://registry-1.docker.io/v2/”:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)2解决办法touch/etc/docker/daemon.......