HTTP gzip壓縮
一. HTTP gzip壓縮,概述
request
header中聲明
Accept-Encoding?: gzip,告知服務(wù)器客戶端接受gzip的數(shù)據(jù)response
body,同時(shí)加入以下header:
Content-Encoding: gzip:表明body是gzip過的數(shù)據(jù)Content-Length:117:表示body gzip壓縮后的數(shù)據(jù)大小,便于客戶端使用或
Transfer-Encoding: chunked:分塊傳輸編碼
二. 如何使用gzip進(jìn)行壓縮
tomcat開啟壓縮(gzip)
tomcat server.xml
??????compression="on"?#?表示開啟壓縮
??????noCompressionUserAgents="gozilla,?traviata"
??????compressionMinSize="2048"?#?表示會(huì)對(duì)大于2KB的文件進(jìn)行壓縮
??????compressableMimeType="text/html,text/xml,text/css,text/javascript,image/gif,image/jpg"?#?是指將進(jìn)行壓縮的文件類型
/>
弊端
對(duì)HTTP傳輸內(nèi)容進(jìn)行壓縮是改良前端響應(yīng)性能的可用方法之一,大型網(wǎng)站都在用。但是也有缺點(diǎn),就是壓縮過程占用cpu的資源,客戶端瀏覽器解析也占據(jù)了一部分時(shí)間。但是隨著硬件性能不斷的提高,這些問題正在不斷的弱化。
程序壓縮/解壓
GZIPInputStream(解壓) / GZIPOutputStream(壓縮)
netflix.zuul相關(guān)示例
#?org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter#writeResponse()
is?=?context.getResponseDataStream();
InputStream?inputStream?=?is;
if?(is?!=?null)?{
????if?(context.sendZuulResponse())?{
????????//?if?origin?response?is?gzipped,?and?client?has?not?requested?gzip,
????????//?decompress?stream
????????//?before?sending?to?client
????????//?else,?stream?gzip?directly?to?client
????????if?(context.getResponseGZipped()?&&?!isGzipRequested)?{
????????????//?If?origin?tell?it's?GZipped?but?the?content?is?ZERO?bytes,
????????????//?don't?try?to?uncompress
????????????final?Long?len?=?context.getOriginContentLength();
????????????if?(len?==?null?||?len?>?0)?{
????????????????try?{
????????????????????inputStream?=?new?GZIPInputStream(is);
????????????????}
????????????????catch?(java.util.zip.ZipException?ex)?{
????????????????????log.debug(
????????????????????????????"gzip?expected?but?not?"
????????????????????????????????????+?"received?assuming?unencoded?response?"
????????????????????????????????????+?RequestContext.getCurrentContext()
????????????????????????????????????.getRequest().getRequestURL()
????????????????????????????????????.toString());
????????????????????inputStream?=?is;
????????????????}
????????????}
????????????else?{
????????????????//?Already?done?:?inputStream?=?is;
????????????}
????????}
????????else?if?(context.getResponseGZipped()?&&?isGzipRequested)?{
????????????servletResponse.setHeader(ZuulHeaders.CONTENT_ENCODING,?"gzip");
????????}
????????writeResponse(inputStream,?outStream);
????}
}
#?com.netflix.zuul.http.HttpServletRequestWrapper.UnitTest#handlesGzipRequestBody
@Test
public?void?handlesGzipRequestBody()?throws?IOException?{
????//?creates?string,?gzips?into?byte?array?which?will?be?mocked?as?InputStream?of?request
????final?String?body?=?"hello";
????final?byte[]?bodyBytes?=?body.getBytes();
????//?in?this?case?the?compressed?stream?is?actually?larger?-?need?to?allocate?enough?space
????final?ByteArrayOutputStream?byteOutStream?=?new?ByteArrayOutputStream(0);
????final?GZIPOutputStream?gzipOutStream?=?new?GZIPOutputStream(byteOutStream);
????gzipOutStream.write(bodyBytes);
????gzipOutStream.finish();
????gzipOutStream.flush();
????body(byteOutStream.toByteArray());
????final?HttpServletRequestWrapper?wrapper?=?new?HttpServletRequestWrapper(request);
????assertEquals(body,?IOUtils.toString(new?GZIPInputStream(wrapper.getInputStream())));
}
示例: 網(wǎng)關(guān)主動(dòng)對(duì)response進(jìn)行壓縮響應(yīng)(可減少帶寬)?GZIPOutputStream
簡(jiǎn)單實(shí)現(xiàn)示例.實(shí)際情況需考慮更新情況,如是否已經(jīng)被壓縮等
InputStream?inputStream?=?okResponse.body().byteStream();
try?{
????//?網(wǎng)關(guān)主動(dòng)對(duì)response進(jìn)行壓縮響應(yīng)(可減少帶寬)
????HttpServletRequest?request?=?RequestContext.getCurrentContext().getRequest();
????boolean?isGatewayGZIP?=?Boolean.parseBoolean(request.getHeader("x-gateway-gzip"));
????if?(!isGatewayGZIP)?{
????????isGatewayGZIP?=?Boolean.parseBoolean(request.getParameter("x-gateway-gzip"));
????}
????if?(isGatewayGZIP)?{
????????final?ByteArrayOutputStream?byteOutStream?=?new?ByteArrayOutputStream(0);
????????final?GZIPOutputStream?gzipOutStream?=?new?GZIPOutputStream(byteOutStream);
????????gzipOutStream.write(okResponse.body().bytes());
????????gzipOutStream.finish();
????????gzipOutStream.flush();
????????inputStream?=?new?ServletInputStreamWrapper(byteOutStream.toByteArray());
????????httpHeaders.add(ZuulHeaders.CONTENT_ENCODING,?"gzip");
????}
}?catch?(Exception?e)?{
????logger.error("GatewayGZIP?error:",?e);
}
三.okhttp 壓縮相關(guān)處理
okHttp 解壓gzip,條件: Content-Encoding = gizp
okio.GzipSource
if?(transparentGzip
????&&?"gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
????&&?HttpHeaders.hasBody(networkResponse))?{
??GzipSource?responseBody?=?new?GzipSource(networkResponse.body().source());
??Headers?strippedHeaders?=?networkResponse.headers().newBuilder()
??????.removeAll("Content-Encoding")
??????.removeAll("Content-Length")
??????.build();
??responseBuilder.headers(strippedHeaders);
??String?contentType?=?networkResponse.header("Content-Type");
??responseBuilder.body(new?RealResponseBody(contentType,?-1L,?Okio.buffer(responseBody)));
}okhttp gzip壓縮/解壓 (示例)
//zip壓縮
GzipSink?gzipSink?=?new?GzipSink(Okio.sink(file));
BufferedSink?bufferedSink?=?Okio.buffer(gzipSink);
bufferedSink.writeUtf8("this?is?zip?file");
bufferedSink.flush();
bufferedSink.close();
//讀取zip
GzipSource?gzipSource?=?new?GzipSource(Okio.source(file));
BufferedSource?bufferedSource?=?Okio.buffer(gzipSource);
String?s?=?bufferedSource.readUtf8();
okhttp框架-如何對(duì)請(qǐng)求(request)數(shù)據(jù)進(jìn)行GZIP壓縮-GzipRequestInterceptor
OkHttpClient?okHttpClient?=?new?OkHttpClient.Builder()?
????.addInterceptor(new?GzipRequestInterceptor())//開啟Gzip壓縮
????...
????.build();
GzipRequestInterceptor
https://github.com/square/okhttp\\issues/350#issuecomment-123105641
class?GzipRequestInterceptor?implements?Interceptor?{
??@Override?public?Response?intercept(Chain?chain)?throws?IOException?{
????Request?originalRequest?=?chain.request();
????if?(originalRequest.body()?==?null?||?originalRequest.header("Content-Encoding")?!=?null)?{
??????return?chain.proceed(originalRequest);
????}
????Request?compressedRequest?=?originalRequest.newBuilder()
????????.header("Content-Encoding",?"gzip")
????????.method(originalRequest.method(),?forceContentLength(gzip(originalRequest.body())))
????????.build();
????return?chain.proceed(compressedRequest);
??}
??/**?https://github.com/square/okhttp\\issues/350?*/
??private?RequestBody?forceContentLength(final?RequestBody?requestBody)?throws?IOException?{
????final?Buffer?buffer?=?new?Buffer();
????requestBody.writeTo(buffer);
????return?new?RequestBody()?{
??????@Override
??????public?MediaType?contentType()?{
????????return?requestBody.contentType();
??????}
??????@Override
??????public?long?contentLength()?{
????????return?buffer.size();
??????}
??????@Override
??????public?void?writeTo(BufferedSink?sink)?throws?IOException?{
????????sink.write(buffer.snapshot());
??????}
????};
??}
??private?RequestBody?gzip(final?RequestBody?body)?{
????return?new?RequestBody()?{
??????@Override?public?MediaType?contentType()?{
????????return?body.contentType();
??????}
??????@Override?public?long?contentLength()?{
????????return?-1;?//?We?don't?know?the?compressed?length?in?advance!
??????}
??????@Override?public?void?writeTo(BufferedSink?sink)?throws?IOException?{
????????BufferedSink?gzipSink?=?Okio.buffer(new?GzipSink(sink));
????????body.writeTo(gzipSink);
????????gzipSink.close();
??????}
????};
??}
}
okhttp框架-如何對(duì)請(qǐng)求數(shù)據(jù)進(jìn)行GZIP壓縮
https://cloud.tencent.com/info/61307ab74137a46628c2ea2ca42a6eb4.html
Okhttp3請(qǐng)求網(wǎng)絡(luò)開啟Gzip壓縮 - CSDN博客
https://blog.csdn.net/aiynmimi/article/details/77453809
四. Nginx的Gzip可以對(duì)服務(wù)器端響應(yīng)內(nèi)容進(jìn)行壓縮從而減少一定的客戶端響應(yīng)時(shí)間
gzip?on;
gzip_min_length?1k;
gzip_buffers?4?32k;
gzip_types?text/plain?application/x-javascript?application/javascript?text/xml?text/css;
gzip_vary?on;
API網(wǎng)關(guān)那些兒 | I'm Yunlong
http://ylzheng.com/2017/03/14/the-things-about-api-gateway
source: //liuxiang.github.io/2018/08/13/HTTP%20gzip壓縮

喜歡,在看
