Brotli压缩、Brotli优势、压缩效率、Android接入Brotli、BrotliInterceptor拦截器

fancie
2023-12-01

一、Brotli 简介

Brotli 是 Google 推出的一种无损压缩算法,通过变种的LZ77算法、Huffman编码以及等方式进行数据压缩。Brotli压缩数据格式的规范在RFC 7932中定义。与其他压缩算法相比(如zip,gzip等),无论是压缩时间,还是压缩体积上看,它都有着更高的效率。
Brotli mailing list:
https://groups.google.com/forum/#! forum/brotli

  • Brotli压缩支持单文件
    支持的文件类型: text/xml、text/plain、text/css、text/javascript、application/javascript、application/x-javascript、application/rss+xml、application/json、application/xml、image/tiff、image/svg+xml
  • 可结合tar, 达到支持文件夹

二、Brotli优势

HTTP的gzip压缩可节省网络流量,提升网络速度,但gzip压缩率还不够高,通过调研,有大量算法压缩率都比gzip高。综合压缩率和实现成本,brotli压缩算法落地成本最低,且业界字节app已有多个域名使用brotli算法。
brotli有11个级别,通过测试发现选用中间级别—7级别比较合适,brotli相对gzip消耗的CPU和内存资源更多,但在可接受范围内。
参考链接:https://juejin.cn/post/7194627379656917047

三、Brotli接入到android

对于 web 和 ios 端,在浏览器和系统层已经开始支持 br 的自动解压了,但 Android 系统不会自动解析 br 数据,需要在应用层自己去实现。
Okhttp 中发现了 BrotliInterceptor 的拦截器,但它是 Brotli 库的 Java 描述,没有真正的 Java 编码器实现。

1. 首先请求头中加入Content-Encoding:br

val request = chain.request().newBuilder()
    .header("Accept-Encoding", "br,gzip")
    .build()

2. OkHttp请求的时候添加拦截器

  1. 直接使用square公司的拦截器
implementation("com.squareup.okhttp3:okhttp-brotli:4.1.0")
OkHttpClient client = new OkHttpClient.Builder()
  .addInterceptor(BrotliInterceptor.INSTANCE)
  .build();
  1. 依赖implementation("org.brotli:dec:0.1.2”),自行实现拦截器
 implementation("org.brotli:dec:0.1.2") //https://mvnrepository.com/artifact/org.brotli/dec

拦截器

object BrotliInterceptor : Interceptor {
  override fun intercept(chain: Interceptor.Chain): Response {
    return if (chain.request().header("Accept-Encoding") == null) {
      val request = chain.request().newBuilder()
        .header("Accept-Encoding", "br,gzip")
        .build()
      val response = chain.proceed(request)
      uncompress(response)
    } else {
      chain.proceed(chain.request())
    }
  }
  fun uncompress(response: Response): Response {
  if (!HttpHeaders.hasBody(response)) {
    	return response
    }
	val body = response.body() ?: return response
  	val encoding = response.header("Content-Encoding") ?: return response
  	val decompressedSource = when {
    encoding.equals("br", ignoreCase = true) ->
      BrotliInputStream(body.source().inputStream()).source().buffer()
    encoding.equals("gzip", ignoreCase = true) ->
      GzipSource(body.source()).buffer()
    else -> return response
  }

  return response.newBuilder()
    .removeHeader("Content-Encoding")
    .removeHeader("Content-Length")
    .body(decompressedSource.asResponseBody(body.contentType(), -1))
    .build()
  }
}

四、Brotli相关GitHub 仓库添加链接描述

https://github.com/google/brotli
https://github.com/square/okhttp

五、写在最后

此文章为个人开发时记录,有时时间有限,无法深入研究,若看到此文章后有其他见解或解决方式,欢迎留言交流

————————————————
版权声明:转载请附上原文出处链接及本声明。
原文链接:
https://blog.csdn.net/weixin_44158429/article/details/130252308

 类似资料: