pako.js对数据进行gzip压缩传递到后台解析,解决数据量大的请求问题

本文来源于简书:使用gzip压缩请求正文

附参照文章所实现的gzipdemo

demo运行效果图如下:
demo运行效果图如下:

实现思路

在前台对请求正文使用 pako_deflate.js 进行本地 gzip 格式压缩
在后台使用 Java 对请求正文进行解压

操作环境

  • jdk 1.8.0_77
  • idea 2016.2.1
  • maven 3.3.9

项目依赖

  • commons-io-2.5 (简化IO操作)
  • json-lib-2.4 (处理请求正文中的参数)
  • spring-webmvc-4.3.4.RELEASE
  • pako_deflate-1.0.3.js (JS文本压缩工具类)

JS 压缩请求正文

因为只在前台进行压缩,所以只需引用 pako 的压缩专用文件 pako_deflate.min.js
又因为我在项目中主要使用 jQuery 发送 Ajax 请求,所以引入 jQuery

<script src="jquery-2.2.4.min.js"></script>
<script src="pako_deflate.min.js"></script>

将发送的参数转换为 JSON 字符串

var params = encodeURIComponent(JSON.stringify({
    title: "标题",
    content: "内容"
}));

gzip 虽然能极大的压缩请求正文.但是如果内容过小,压缩后内容反而会增大,经测试,对于 params.length 大于 1000 的文本压缩效果能够达到 60% 以上,所以在压缩前,需要对内容进行判断

var params = encodeURIComponent(JSON.stringify({
    title: title,
    content: content
}));
var compressBeginLen = params.length;
if (compressBeginLen > 1000) {
    //对 JSON 字符串进行压缩
    // pako.gzip(params) 默认返回一个 Uint8Array 对象,如果此时使用 Ajax 进行请求,参数会以数组的形式进行发送
    // 为了解决该问题,添加 {to: "string"} 参数,返回一个二进制的字符串
    params = pako.gzip(params, {to: "string"});
}
$.ajax({
    url: "/gzip",
    data: params,
    dataType: "text",
    type: "post",
    headers: {
        //如果 compressBeginLen 大于 1000,标记此次请求的参数使用了 gzip 压缩
        "Content-Encoding": params.length>1000?"gzip":""
    },
    success: function (data) {
        //dosomething
    }
})

Java 解压请求正文

首先获取 Content-Encoding 请求头,根据该请求头中的内容进行逻辑处理

@ResponseBody
@RequestMapping(value = "/gzip")
public String gzip(HttpServletRequest request) {
    String params = "";
    try {
        //获取 Content-Encoding 请求头
        String contentEncoding = request.getHeader("Content-Encoding");
        if (contentEncoding != null && contentEncoding.equals("gzip")) {
            //获取输入流
            BufferedReader reader = request.getReader();
            //将输入流中的请求实体转换为byte数组,进行gzip解压
            byte[] bytes = IOUtils.toByteArray(reader, "iso-8859-1");
            //对 bytes 数组进行解压
            params = GZIPUtil.uncompress(bytes);
        } else {
            BufferedReader reader = request.getReader();
            params = IOUtils.toString(reader);
        }
        if (params != null && params.trim().length() > 0) {
            //因为前台对参数进行了 url 编码,在此进行解码
            params = URLDecoder.decode(params, "utf-8");
            //将解码后的参数转换为 json 对象
            JSONObject json = JSONObject.fromObject(params);
            //从 json 对象中获取参数进行后续操作
            System.out.println("title:\t" + json.getString("title"));
            System.out.println("content:\t" + json.getString("content"));
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return params;
}

Java gzip 解压方法 GZIPUtil.uncompress 参考 Java 使用 GZIP 进行压缩和解压缩(GZIPOutputStream,GZIPInputStream) 一文而成

/**
 * 解压gzip格式byte数组
 * @param bytes gzip格式byte数组
 * @param charset 字符集
 */
public static String uncompress(byte[] bytes, String charset) {
    if (bytes == null || bytes.length == 0) {
        return null;
    }
    ByteArrayOutputStream byteArrayOutputStream = null;
    ByteArrayInputStream byteArrayInputStream = null;
    GZIPInputStream gzipInputStream = null;
    try {
        byteArrayOutputStream = new ByteArrayOutputStream();
        byteArrayInputStream = new ByteArrayInputStream(bytes);
        gzipInputStream = new GZIPInputStream(byteArrayInputStream);
        //使用org.apache.commons.io.IOUtils 简化流的操作
        IOUtils.copy(gzipInputStream, byteArrayOutputStream);
        return byteArrayOutputStream.toString(charset);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //释放流资源
        IOUtils.closeQuietly(gzipInputStream);
        IOUtils.closeQuietly(byteArrayInputStream);
        IOUtils.closeQuietly(byteArrayOutputStream);
    }
    return null;
}

另外 Jerry Qu 实现了一个服务器使用 Node.js 解压的 DEMO 并提供 deflate,zlib,gzip 三种压缩,解压方式
以上完整代码可在 gzip 项目中查看




  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
在Java后端和浏览器中使用Pako.js实现Gzip压缩和解压方法是不同的。 浏览器端: 压缩: ``` var buffer = new Uint8Array(inputString.length); for (var i = 0; i < inputString.length; i++) { buffer[i] = inputString.charCodeAt(i); } var compressed = pako.gzip(buffer); var outputString = String.fromCharCode.apply(null, new Uint16Array(compressed)); ``` 解压: ``` var compressed = new Uint8Array(inputString.length); for (var i = 0; i < inputString.length; i++) { compressed[i] = inputString.charCodeAt(i); } var decompressed = pako.inflate(compressed); var outputString = String.fromCharCode.apply(null, new Uint16Array(decompressed)); ``` 与在浏览器端相同,我们首先将输入字符串转换为一个Uint8Array,然后使用Pako.jsgzip函数将其压缩。最后,我们将压缩后的结果转换回字符串形式。 在解压的过程中,我们将输入字符串转换为Uint8Array,然后使用Pako.js的inflate函数将其解压,最后将结果转换回字符串形式。 需要注意的是,最后转换为字符串时要使用Uint16Array而不是Uint8Array,这是因为JavaScript中的字符串是基于UTF-16编码的。 Java后端: Java后端可以使用Java版的Pako库实现Gzip压缩和解压。 引入Java版的Pako库: ``` <dependency> <groupId>io.github.azagniotov</groupId> <artifactId>pako-java</artifactId> <version>1.0.1</version> </dependency> ``` 压缩: ``` String inputString = "input string"; byte[] inputBytes = inputString.getBytes(StandardCharsets.UTF_8); byte[] compressedBytes = new Deflater().deflate(inputBytes); String outputString = new String(compressedBytes, StandardCharsets.ISO_8859_1); ``` 解压: ``` byte[] compressedBytes = inputString.getBytes(StandardCharsets.ISO_8859_1); Inflater inflater = new Inflater(); inflater.setInput(compressedBytes); byte[] buffer = new byte[1024]; ByteArrayOutputStream outputStream = new ByteArrayOutputStream(compressedBytes.length); while (!inflater.finished()) { int count = inflater.inflate(buffer); outputStream.write(buffer, 0, count); } outputStream.close(); byte[] decompressedBytes = outputStream.toByteArray(); String outputString = new String(decompressedBytes, StandardCharsets.UTF_8); ``` 在Java中,我们使用Deflater类的deflate方法进行压缩,使用Inflater类进行解压。需要注意的是,在解压的过程中,我们需要使用一个字节输出流ByteArrayOutputStream来存储解压后的字节,最后再将其转换为字符串形式。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值