当前位置:   article > 正文

HTTP gzip压缩

gzipsource

3c54288020327fd09529ee9087eb77f5.png

一. HTTP gzip压缩,概述

  • request

    • header中声明Accept-Encoding : gzip,告知服务器客户端接受gzip的数据

  • response

    • body,同时加入以下header:Content-Encoding: gzip:表明body是gzip过的数据

    • Content-Length:117:表示body gzip压缩后的数据大小,便于客户端使用

    • Transfer-Encoding: chunked:分块传输编码

二. 如何使用gzip进行压缩

tomcat开启压缩(gzip)

tomcat server.xml

  1. <Connector
  2.       compression="on" # 表示开启压缩
  3.       noCompressionUserAgents="gozilla, traviata"
  4.       compressionMinSize="2048" # 表示会对大于2KB的文件进行压缩
  5.       compressableMimeType="text/html,text/xml,text/css,text/javascript,image/gif,image/jpg" # 是指将进行压缩的文件类型
  6. />
  • 弊端
    对HTTP传输内容进行压缩是改良前端响应性能的可用方法之一,大型网站都在用。但是也有缺点,就是压缩过程占用cpu的资源,客户端浏览器解析也占据了一部分时间。但是随着硬件性能不断的提高,这些问题正在不断的弱化。

程序压缩/解压

GZIPInputStream(解压) / GZIPOutputStream(压缩)

  • netflix.zuul相关示例

  1. # org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter#writeResponse()
  2. is = context.getResponseDataStream();
  3. InputStream inputStream = is;
  4. if (is != null) {
  5.     if (context.sendZuulResponse()) {
  6.         // if origin response is gzipped, and client has not requested gzip,
  7.         // decompress stream
  8.         // before sending to client
  9.         // else, stream gzip directly to client
  10.         if (context.getResponseGZipped() && !isGzipRequested) {
  11.             // If origin tell it's GZipped but the content is ZERO bytes,
  12.             // don't try to uncompress
  13.             final Long len = context.getOriginContentLength();
  14.             if (len == null || len > 0) {
  15.                 try {
  16.                     inputStream = new GZIPInputStream(is);
  17.                 }
  18.                 catch (java.util.zip.ZipException ex) {
  19.                     log.debug(
  20.                             "gzip expected but not "
  21.                                     + "received assuming unencoded response "
  22.                                     + RequestContext.getCurrentContext()
  23.                                     .getRequest().getRequestURL()
  24.                                     .toString());
  25.                     inputStream = is;
  26.                 }
  27.             }
  28.             else {
  29.                 // Already done : inputStream = is;
  30.             }
  31.         }
  32.         else if (context.getResponseGZipped() && isGzipRequested) {
  33.             servletResponse.setHeader(ZuulHeaders.CONTENT_ENCODING, "gzip");
  34.         }
  35.         writeResponse(inputStream, outStream);
  36.     }
  37. }
  38. # com.netflix.zuul.http.HttpServletRequestWrapper.UnitTest#handlesGzipRequestBody
  39. @Test
  40. public void handlesGzipRequestBody() throws IOException {
  41.     // creates string, gzips into byte array which will be mocked as InputStream of request
  42.     final String body = "hello";
  43.     final byte[] bodyBytes = body.getBytes();
  44.     // in this case the compressed stream is actually larger - need to allocate enough space
  45.     final ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream(0);
  46.     final GZIPOutputStream gzipOutStream = new GZIPOutputStream(byteOutStream);
  47.     gzipOutStream.write(bodyBytes);
  48.     gzipOutStream.finish();
  49.     gzipOutStream.flush();
  50.     body(byteOutStream.toByteArray());
  51.     final HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper(request);
  52.     assertEquals(body, IOUtils.toString(new GZIPInputStream(wrapper.getInputStream())));
  53. }

示例: 网关主动对response进行压缩响应(可减少带宽) GZIPOutputStream

  • 简单实现示例.实际情况需考虑更新情况,如是否已经被压缩等

  1. InputStream inputStream = okResponse.body().byteStream();
  2. try {
  3.     // 网关主动对response进行压缩响应(可减少带宽)
  4.     HttpServletRequest request = RequestContext.getCurrentContext().getRequest();
  5.     boolean isGatewayGZIP = Boolean.parseBoolean(request.getHeader("x-gateway-gzip"));
  6.     if (!isGatewayGZIP) {
  7.         isGatewayGZIP = Boolean.parseBoolean(request.getParameter("x-gateway-gzip"));
  8.     }
  9.     if (isGatewayGZIP) {
  10.         final ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream(0);
  11.         final GZIPOutputStream gzipOutStream = new GZIPOutputStream(byteOutStream);
  12.         gzipOutStream.write(okResponse.body().bytes());
  13.         gzipOutStream.finish();
  14.         gzipOutStream.flush();
  15.         inputStream = new ServletInputStreamWrapper(byteOutStream.toByteArray());
  16.         httpHeaders.add(ZuulHeaders.CONTENT_ENCODING, "gzip");
  17.     }
  18. } catch (Exception e) {
  19.     logger.error("GatewayGZIP error:", e);
  20. }

三.okhttp 压缩相关处理

okHttp 解压gzip,条件: Content-Encoding = gizp

  • okio.GzipSource

  1. if (transparentGzip
  2.     && "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
  3.     && HttpHeaders.hasBody(networkResponse)) {
  4.   GzipSource responseBody = new GzipSource(networkResponse.body().source());
  5.   Headers strippedHeaders = networkResponse.headers().newBuilder()
  6.       .removeAll("Content-Encoding")
  7.       .removeAll("Content-Length")
  8.       .build();
  9.   responseBuilder.headers(strippedHeaders);
  10.   String contentType = networkResponse.header("Content-Type");
  11.   responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
  12. }

okhttp gzip压缩/解压 (示例)

  1. //zip压缩
  2. GzipSink gzipSink = new GzipSink(Okio.sink(file));
  3. BufferedSink bufferedSink = Okio.buffer(gzipSink);
  4. bufferedSink.writeUtf8("this is zip file");
  5. bufferedSink.flush();
  6. bufferedSink.close();
  7. //读取zip
  8. GzipSource gzipSource = new GzipSource(Okio.source(file));
  9. BufferedSource bufferedSource = Okio.buffer(gzipSource);
  10. String s = bufferedSource.readUtf8();

okhttp框架-如何对请求(request)数据进行GZIP压缩-GzipRequestInterceptor

  1. OkHttpClient okHttpClient = new OkHttpClient.Builder() 
  2.     .addInterceptor(new GzipRequestInterceptor())//开启Gzip压缩
  3.     ...
  4.     .build();

GzipRequestInterceptor
https://github.com/square/okhttp\\issues/350#issuecomment-123105641

  1. class GzipRequestInterceptor implements Interceptor {
  2.   @Override public Response intercept(Chain chain) throws IOException {
  3.     Request originalRequest = chain.request();
  4.     if (originalRequest.body() == null || originalRequest.header("Content-Encoding") != null) {
  5.       return chain.proceed(originalRequest);
  6.     }
  7.     Request compressedRequest = originalRequest.newBuilder()
  8.         .header("Content-Encoding""gzip")
  9.         .method(originalRequest.method(), forceContentLength(gzip(originalRequest.body())))
  10.         .build();
  11.     return chain.proceed(compressedRequest);
  12.   }
  13.   /** https://github.com/square/okhttp\\issues/350 */
  14.   private RequestBody forceContentLength(final RequestBody requestBody) throws IOException {
  15.     final Buffer buffer = new Buffer();
  16.     requestBody.writeTo(buffer);
  17.     return new RequestBody() {
  18.       @Override
  19.       public MediaType contentType() {
  20.         return requestBody.contentType();
  21.       }
  22.       @Override
  23.       public long contentLength() {
  24.         return buffer.size();
  25.       }
  26.       @Override
  27.       public void writeTo(BufferedSink sink) throws IOException {
  28.         sink.write(buffer.snapshot());
  29.       }
  30.     };
  31.   }
  32.   private RequestBody gzip(final RequestBody body) {
  33.     return new RequestBody() {
  34.       @Override public MediaType contentType() {
  35.         return body.contentType();
  36.       }
  37.       @Override public long contentLength() {
  38.         return -1// We don't know the compressed length in advance!
  39.       }
  40.       @Override public void writeTo(BufferedSink sink) throws IOException {
  41.         BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
  42.         body.writeTo(gzipSink);
  43.         gzipSink.close();
  44.       }
  45.     };
  46.   }
  47. }

okhttp框架-如何对请求数据进行GZIP压缩
https://cloud.tencent.com/info/61307ab74137a46628c2ea2ca42a6eb4.html

Okhttp3请求网络开启Gzip压缩 - CSDN博客
https://blog.csdn.net/aiynmimi/article/details/77453809

四. Nginx的Gzip可以对服务器端响应内容进行压缩从而减少一定的客户端响应时间

  1. gzip on;
  2. gzip_min_length 1k;
  3. gzip_buffers 4 32k;
  4. gzip_types text/plain application/x-javascript application/javascript text/xml text/css;
  5. gzip_vary on;

API网关那些儿 | I'm Yunlong
http://ylzheng.com/2017/03/14/the-things-about-api-gateway

source: //liuxiang.github.io/2018/08/13/HTTP%20gzip压缩

bd29d43df85ad8e3b878dd25ef065e82.png

喜欢,在看

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/1002252
推荐阅读
相关标签
  

闽ICP备14008679号