• 【实习】解决请求参数过长问题


    又要解决bug啦!!!
    在这里插入图片描述

    由于前端传过来的json数据过长导致请求参数太长,最后出现空指针异常。
    HTTP/1.1 414 Request-URI Too Large

    解决方法:
    参考:Java使用GZIP进行压缩和解压缩(GZIPOutputStream,GZIPInputStream)
    使用gzip压缩/解压缩字符串

    一、使用gzip压缩字符串(str 要压缩的字符串)

    在这里插入图片描述

    参考:
    Java ByteArrayOutputStream类

    //创建一个32字节(默认大小)的缓冲区
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    
    • 1
    • 2

    源码:
    在这里插入图片描述

    //创建具有默认缓冲区大小out的新字节数组输出流对象。
    GZIPOutputStream gzip = new GZIPOutputStream(out);
    
    • 1
    • 2

    参考:
    Java_io体系之FilterInputStream/FilterOutputStream简介、走进源码及示例——07
    在这里插入图片描述
    源码:
    创建具有默认缓冲区大小的新输出流。
    新的输出流实例是通过调用2参数构造函数GZIPOutputStream(out,false)创建的。

    在这里插入图片描述

    使用默认缓冲区大小和指定的刷新模式创建新的输出流。
    参数:
    out–输出流syncFlush–如果此实例的继承flush()方法的调用为true,则使用flush mode Deflater刷新压缩器。在刷新输出流之前进行SYNC\u刷新,否则仅刷新输出流.
    在这里插入图片描述

    gzip.write(str.getBytes());
    
    • 1

    getBytes() 是Java编程语言中将一个字符串转化为一个字节数组byte[]的方法。

    	//getBytes() 源码:
    	public byte[] getBytes() {
            return StringCoding.encode(value, off:0, value.length);
        }
    
    • 1
    • 2
    • 3
    • 4

    write源码:
    将b.length字节写入此输出流。
    FilterOutputStream的write方法使用参数b、0和b.length调用其三个参数的write方法。
    注意,该方法不使用单参数b调用其底层流的单参数write方法。
    在这里插入图片描述

    其三个参数的write方法源码:
    从偏移量off开始,将指定字节数组中的len字节写入此输出流。
    FilterOutputStream的write方法调用每个字节上一个参数的write方法进行输出。
    请注意,此方法不会使用相同的参数调用其底层输入流的write方法。FilterOutputStream的子类应提供此方法的更有效实现。
    在这里插入图片描述

    将指定的字节写入此输出流。
    FilterOutputStream的write方法调用其底层输出流的write方法,即执行。写入(b)。实现OutputStream的抽象写入方法。
    在这里插入图片描述

    将指定的字节写入此输出流。
    写入的一般约定是将一个字节写入输出流。要写入的字节是参数b的八个低位。忽略b的24个高位。OutputStream的子类必须提供此方法的实现。
    在这里插入图片描述

    if (gzip != null) {
    	try {
    		gzip.close();
    	} catch (IOException e) {
    		e.printStackTrace();
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    close源码:
    将剩余的压缩数据写入输出流并关闭底层流。

    private boolean closed = false;
    boolean usesDefaultDeflater = false;
    
    • 1
    • 2

    在这里插入图片描述

    将压缩数据写入输出流而不关闭底层流。
    当对同一输出流连续应用多个过滤器时,请使用此方法。
    在这里插入图片描述
    关闭压缩机并丢弃任何未处理的输入。当压缩器不再使用时,应调用此方法,但也将由finalize()方法自动调用。调用此方法后,Deflater对象的行为未定义。
    在这里插入图片描述

    关闭此输出流并释放与此流关联的任何系统资源。
    关闭的一般约定是关闭输出流。关闭的流无法执行输出操作,也无法重新打开。
    OutputStream的close方法不起任何作用。
    在这里插入图片描述

    //编码-压缩
    return new sun.misc.BASE64Encoder().encode(out.toByteArray());
    
    • 1
    • 2

    参考:

    在JAVA中要实现Base64的编码和解码是非常容易的,因为JDK中已经有提供有现成的类:

    //编码:
    String src ="BASE64编码测试";  
    sun.misc.BASE64Encoder en = new sun.misc.BASE64Encoder(); 
    String encodeStr = en.encode(src.getBytes());     
    
    //解码:
    sun.misc.BASE64Decoder dec = newsun.misc.BASE64Decoder(); 
    byte[] data = dec.decodeBuffer(decodeStr); 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    二、使用gzip解压缩(compressedStr 压缩字符串)

    在这里插入图片描述
    在这里插入图片描述

    //初始化,建立默认大小的缓冲分区
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    ByteArrayInputStream in = null;
    GZIPInputStream ginzip = null;
    byte[] compressed = null;
    String decompressed = null;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    //decodeBuffer()解码
    compressed = new sun.misc.BASE64Decoder().decodeBuffer(compressedStr);
    
    • 1
    • 2

     in = new ByteArrayInputStream(compressed);
    
    • 1

    创建ByteArrayInputStream,以便使用buf作为其缓冲区数组。未复制缓冲区阵列。pos的初始值为0,count的初始值为buf的长度。
    在这里插入图片描述

    ginzip = new GZIPInputStream(in);
    
    • 1

    创建具有默认缓冲区大小的新输入流。
    在这里插入图片描述

    while ((offset = ginzip.read(buffer)) != -1) {
    	out.write(buffer, 0, offset);
    }
    
    • 1
    • 2
    • 3

    最多读取字节。将此输入流中的数据长度字节设置为字节数组。此方法会阻塞,直到有一些输入可用。
    该方法只执行调用读取(b,0,b.length)并返回结果。重要的是,它不适用于。改为(b);FilterInputStream的某些子类取决于实际使用的实现策略。
    在这里插入图片描述
    从该输入流中读取多达len个字节的数据到一个字节数组中。如果len不为零,该方法将阻塞,直到有一些输入可用;否则,不读取任何字节,并返回0。
    此方法仅在中执行。读取(b,off,len)并返回结果。
    参数:
    b–读取数据的缓冲区。off–目标阵列b len中的开始偏移量–读取的最大字节数。
    在这里插入图片描述

    从偏移量off开始,将指定字节数组中的len字节写入此字节数组输出流。
    在这里插入图片描述

    //转换为String类型
    decompressed = out.toString();
    
    • 1
    • 2

    针对java,注意:

    • 如果项目的JDK版本小于1.8,请使用org.apache.commons.codec.binary.Base64;
    • 如果项目的JDK版本大于1.8,请使用java.util.Base64;
    • 使用org.apache.commons.codec.binary.Base64时,要选择与项目JDK相符的JAR包,否则实现不了效果;
    • java.util.Base64与org.apache.commons.codec.binary.Base64包冲突,不能同时存在一个类中;
    • 注意,UTF-8和GBK中文格式的Base64编码结果是不同的。

    三、修改service实现类-Json转换为sql方法中conditionJson的压缩格式

    原来:

    params.put("conditionJson", URLEncoder.encode(tagInfo.getGenerationLogic(),"UTF-8")); //  conditionJson条件json字段 同 生成逻辑字段:generationLogic
    
    • 1

    修改后: 请求url的时候经过压缩后的参数不会过长

    //压缩后的逻辑json
    String compressGenerationLogic = CompressUtil.compress(tagInfo.getGenerationLogic());
    params.put("conditionJson", URLEncoder.encode(Base64.encodeBase64String(compressGenerationLogic.getBytes()),"UTF-8")); 
    
    • 1
    • 2
    • 3

    URLEncoder.encode(String s, String enc):
    s–要翻译的字符串。enc–支持的字符编码的名称。

    URLEncoder.encode(tagInfo.getGenerationLogic(),"UTF-8")
    
    • 1

    使用特定的编码方案将字符串转换为application/x-www-form-urlencoded格式。此方法使用提供的编码方案来获取不安全字符的字节。

    String encode(String s, String enc)
    
    • 1

    使用base64算法对二进制数据进行编码,但不将输出分块。
    注:我们将该方法的行为从多行分块(commons-codec-1.4)更改为单行非分块(commons-codec-1.5)。
    在这里插入图片描述
    使用base64算法对二进制数据进行编码,可以选择将输出分块为76个字符块。
    isChunked–如果为true,则此编码器将base64输出分为76个字符块
    在这里插入图片描述

    使用base64算法对二进制数据进行编码,可以选择将输出分块为76个字符块。
    参数:
    binaryData–包含要编码的二进制数据的数组。
    isChunked–如果为true,则此编码器将base64输出分为76个字符块
    urlSafe–如果为true,则此编码器将发出-和_而不是通常的+和/字符。注意:使用URL安全字母表编码时不添加填充。
    在这里插入图片描述

    使用base64算法对二进制数据进行编码,可以选择将输出分块为76个字符块。
    参数:
    binaryData–包含要编码的二进制数据的数组。
    isChunked–如果为true,则此编码器将base64输出分为76个字符块
    urlSafe–如果为true,则此编码器将发出-和_而不是通常的+和/字符。
    注意:使用URL安全字母表编码时不添加填充。
    maxResultSize–要接受的最大结果大小。
    在这里插入图片描述

    四、修改Controller的接口

    往request中添加条件json—是解压缩后的。
    在这里插入图片描述

    String decodeConditionJson = new String(Base64.decodeBase64(request.getConditionJson()));
    request.setConditionJson(CompressUtil.uncompress(decodeConditionJson));
    
    • 1
    • 2

    将Base64字符串解码为八位字节:
    在这里插入图片描述
    解码包含N进制字母中字符的字符串。
    在这里插入图片描述

    解码包含N进制字母中字符的字节数组。
    在这里插入图片描述

    发送端在数据发送前的处理流程如下(接收端互逆):
    1.先对原始字符串签名,以保证签名忠实于原始内容;
    2.然后压缩,以精简内容的尺寸,提高后续加密和传输的效率;
    3.最后加密,保证数据安全。

  • 相关阅读:
    JavaScript对象和函数——JavaScript筑基
    小程序源码:首席省钱赚钱专家微信小程序源码下载,淘宝客 外卖侠 外卖cps 首席多多客 八合一小程序源码
    简单实现spring的set依赖注入
    大数据----Hadoop与数据仓库
    【腾讯云Cloud Studio实战训练营】戏说cloud studio
    大部分人都不知道产品说明书有这些特点
    判断一份好的问卷有哪些标准?
    通过sls采集k8s集群上的服务日志
    JQuery UI——滑动条组件
    springboot 配置文件编写 自定义参数 配置提示功能 配置处理器
  • 原文地址:https://blog.csdn.net/m0_58058653/article/details/125558584