GZIP压缩提高网络传输效率

时间:2022-05-04 06:54:58

【spring】通过GZIP压缩提高网络传输效率(可以实现任何资源的gzip压缩、包括AJAX)

gzip是http协议中使用的一种加密算法,客户端向web服务器端发出了请求后,通常情况下服务器端会将页面文件和其他资源,返回到客户端,客户端加载后渲染呈现,这种情况文件一般都比较大,如果开启Gzip ,那么服务器端响应后,会将页面,JS,CSS等文本文件或者其他文件通过高压缩算法将其压缩,然后传输到客户端,由客户端的浏览器负责解压缩与呈现。通常能节省40%以上的流量(一般都有60%左右),一些PHP,JSP文件也能够进行压缩。

1、通过WEB服务器打开GZIP压缩服务

目前大多数主流WEB中间件都支持GZIP压缩、下面以Tomcat 为例进行说明:

找到Tomcat 目录下的conf下的server.xml,并找到如下信息

      <Connector port = "8080" maxHttpHeaderSize = "8192" maxThreads = "150" minSpareThreads = "25"
              maxSpareThreads = "75" enableLookups = "false" redirectPort = "8443" acceptCount = "100"
              connectionTimeout = "20000" disableUploadTimeout = "true"

将它改成如下的形式(其实在上面代码的下面已经有了,将他们打开而已。):

      <Connector port="8080" maxHttpHeaderSize="8192" maxThreads="150" minSpareThreads="25"
             maxSpareThreads="75" enableLookups="false" redirectPort="8443" acceptCount="100"
             connectionTimeout="20000" disableUploadTimeout="true"
             compression="on" compressionMinSize="2048" noCompressionUserAgents="gozilla, traviata"
             compressableMimeType="text/html,text/xml" >

这样,就能够对html和xml进行压缩了,如果要压缩css 和 js,那么需要将

compressableMimeType=”text/html,text/xml”加入css和js:

           <Connector port="8080" ......... compressableMimeType="text/html,text/xml,text/css,text/javascript" >

一般文本类型的静态文件可以通过这种方式压缩后传输、提高传输效率。

已压缩过的静态文件(如图片)进行gzip压缩后大小基本无变化、所以一般不进行压缩。

2、通过过滤器实现gzip压缩

  1. package com.tyyd.framework.web;
  2. import java.io.IOException;
  3. import javax.servlet.Filter;
  4. import javax.servlet.FilterChain;
  5. import javax.servlet.FilterConfig;
  6. import javax.servlet.ServletException;
  7. import javax.servlet.ServletOutputStream;
  8. import javax.servlet.ServletRequest;
  9. import javax.servlet.ServletResponse;
  10. import javax.servlet.http.HttpServletRequest;
  11. import javax.servlet.http.HttpServletResponse;
  12. import org.apache.commons.io.FilenameUtils;
  13. import org.apache.commons.lang.StringUtils;
  14. import com.tyyd.framework.core.AcwsInfo;
  15. import com.tyyd.framework.core.AcwsMonitorLog;
  16. import com.tyyd.framework.core.BufferedResponse;
  17. import com.tyyd.framework.core.util.ZipUtil;
  18. /**
  19. * HTTP访问过滤器
  20. */
  21. public class PageVisitFilter2 implements Filter {
  22. @Override
  23. public void init(FilterConfig filterConfig) throws ServletException {
  24. }
  25. @Override
  26. public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
  27. //性能监控
  28. long startTime = System.currentTimeMillis();
  29. HttpServletRequest request = (HttpServletRequest)req;
  30. HttpServletResponse response = (HttpServletResponse)res;
  31. String uri = request.getRequestURI();
  32. String ext = FilenameUtils.getExtension(uri);
  33. try{
  34. response.setHeader("Pragma", "No-cache");
  35. response.setHeader("Cache-Control", "no-cache");
  36. response.setDateHeader("Expires", -1);
  37. request.setCharacterEncoding("UTF-8");
  38. response.setCharacterEncoding("UTF-8");
  39. response.setHeader("renderer", "webkit");
  40. response.setHeader("viewport", "width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0 user-scalable=no");
  41. if(isGZipEncoding(request)){
  42. //需要过滤的扩展名:.htm,.html,.jsp,.js,.ajax,.css
  43. String gzippPattern=",.htm,.html,.jsp,.js,.ajax,.css,";
  44. if(StringUtils.indexOf(gzippPattern, ",."+ext+",")!=-1){
  45. BufferedResponse gzipResponse = new BufferedResponse(response);
  46. chain.doFilter(request, gzipResponse);
  47. byte[] srcData = gzipResponse.getResponseData();
  48. byte[] outData = null;
  49. if(srcData.length > 512){
  50. byte[] gzipData = ZipUtil.toGzipBytes(srcData);
  51. response.addHeader("Content-Encoding", "gzip");
  52. response.setContentLength(gzipData.length);
  53. outData = gzipData;
  54. } else {
  55. outData = srcData;
  56. }
  57. ServletOutputStream output = response.getOutputStream();
  58. output.write(outData);
  59. output.flush();
  60. } else {
  61. chain.doFilter(request, response);
  62. }
  63. return;
  64. }
  65. chain.doFilter(request, response);
  66. }catch(Exception e){
  67. }finally{
  68. AcwsMonitorLog.warnHttpVisit(startTime, request);
  69. }
  70. }
  71. @Override
  72. public void destroy() {
  73. }
  74. /**
  75. * 判断浏览器是否支持GZIP
  76. * @param request
  77. * @return
  78. */
  79. private boolean isGZipEncoding(HttpServletRequest request){
  80. boolean flag=false;
  81. String encoding=request.getHeader("Accept-Encoding");
  82. if(encoding.indexOf("gzip")!=-1){
  83. flag=true;
  84. }
  85. return flag;
  86. }
  87. }
  1. package com.tyyd.framework.core;
  2. import java.io.IOException;
  3. import java.io.OutputStreamWriter;
  4. import java.io.PrintWriter;
  5. import javax.servlet.ServletOutputStream;
  6. import javax.servlet.http.HttpServletResponse;
  7. import javax.servlet.http.HttpServletResponseWrapper;
  8. public class BufferedResponse extends HttpServletResponseWrapper {
  9. public static final int OT_NONE = 0, OT_WRITER = 1, OT_STREAM = 2;
  10. private BufferedOutputStream outputStream = null;
  11. private PrintWriter writer = null;
  12. private int outputType = OT_NONE;
  13. public BufferedResponse(HttpServletResponse response) {
  14. super(response);
  15. outputStream = new BufferedOutputStream();
  16. }
  17. public PrintWriter getWriter() throws IOException {
  18. if (outputType == OT_STREAM)
  19. throw new IllegalStateException();
  20. else if (outputType == OT_WRITER)
  21. return writer;
  22. else {
  23. outputType = OT_WRITER;
  24. writer = new PrintWriter(new OutputStreamWriter(outputStream,
  25. getCharacterEncoding()), true);
  26. return writer;
  27. }
  28. }
  29. public ServletOutputStream getOutputStream() throws IOException {
  30. if (outputType == OT_WRITER)
  31. throw new IllegalStateException();
  32. else if (outputType == OT_STREAM)
  33. return outputStream;
  34. else {
  35. outputType = OT_STREAM;
  36. return outputStream;
  37. }
  38. }
  39. public void flushBuffer() throws IOException {
  40. try{writer.flush();}catch(Exception e){}
  41. try{outputStream.flush();}catch(Exception e){}
  42. }
  43. public void reset() {
  44. outputType = OT_NONE;
  45. outputStream.reset();
  46. }
  47. public byte[] getResponseData() throws IOException {
  48. flushBuffer();
  49. return outputStream.toByteArray();
  50. }
  51. }
  1. /**
  2. * 版权所有:
  3. * 项目名称:框架
  4. * 创建者: Wangdf
  5. * 创建日期: 2015-2-27
  6. * 文件说明: AJAX 缓存输出流
  7. */
  8. package com.tyyd.framework.core;
  9. import java.io.ByteArrayOutputStream;
  10. import java.io.IOException;
  11. import javax.servlet.ServletOutputStream;
  12. public class BufferedOutputStream extends ServletOutputStream {
  13. private ByteArrayOutputStream outputStream = null;
  14. public BufferedOutputStream(){
  15. outputStream = new ByteArrayOutputStream(1024);
  16. }
  17. /**
  18. * Writes the specified byte to this output stream. The general
  19. * contract for <code>write</code> is that one byte is written
  20. * to the output stream. The byte to be written is the eight
  21. * low-order bits of the argument <code>b</code>. The 24
  22. * high-order bits of <code>b</code> are ignored.
  23. * <p>
  24. * Subclasses of <code>OutputStream</code> must provide an
  25. * implementation for this method.
  26. *
  27. * @param      b   the <code>byte</code>.
  28. * @exception  IOException  if an I/O error occurs. In particular,
  29. *             an <code>IOException</code> may be thrown if the
  30. *             output stream has been closed.
  31. */
  32. public void write(int b) throws IOException {
  33. outputStream.write(b);
  34. }
  35. /**
  36. * Writes <code>b.length</code> bytes from the specified byte array
  37. * to this output stream. The general contract for <code>write(b)</code>
  38. * is that it should have exactly the same effect as the call
  39. * <code>write(b, 0, b.length)</code>.
  40. *
  41. * @param      b   the data.
  42. * @exception  IOException  if an I/O error occurs.
  43. * @see        java.io.OutputStream#write(byte[], int, int)
  44. */
  45. public void write(byte b[]) throws IOException {
  46. outputStream.write(b);
  47. }
  48. /**
  49. * Writes <code>len</code> bytes from the specified byte array
  50. * starting at offset <code>off</code> to this output stream.
  51. * The general contract for <code>write(b, off, len)</code> is that
  52. * some of the bytes in the array <code>b</code> are written to the
  53. * output stream in order; element <code>b[off]</code> is the first
  54. * byte written and <code>b[off+len-1]</code> is the last byte written
  55. * by this operation.
  56. * <p>
  57. * The <code>write</code> method of <code>OutputStream</code> calls
  58. * the write method of one argument on each of the bytes to be
  59. * written out. Subclasses are encouraged to override this method and
  60. * provide a more efficient implementation.
  61. * <p>
  62. * If <code>b</code> is <code>null</code>, a
  63. * <code>NullPointerException</code> is thrown.
  64. * <p>
  65. * If <code>off</code> is negative, or <code>len</code> is negative, or
  66. * <code>off+len</code> is greater than the length of the array
  67. * <code>b</code>, then an <tt>IndexOutOfBoundsException</tt> is thrown.
  68. *
  69. * @param      b     the data.
  70. * @param      off   the start offset in the data.
  71. * @param      len   the number of bytes to write.
  72. * @exception  IOException  if an I/O error occurs. In particular,
  73. *             an <code>IOException</code> is thrown if the output
  74. *             stream is closed.
  75. */
  76. public void write(byte b[], int off, int len) throws IOException {
  77. outputStream.write(b, off, len);
  78. }
  79. /**
  80. * Writes a <code>String</code> to the client,
  81. * without a carriage return-line feed (CRLF)
  82. * character at the end.
  83. *
  84. *
  85. * @param s         the <code>String</code> to send to the client
  86. *
  87. * @exception IOException   if an input or output exception occurred
  88. *
  89. */
  90. public void print(String s) throws IOException {
  91. print(s, "UTF-8");
  92. }
  93. public void print(String s, String charsetName) throws IOException {
  94. /*
  95. * 解决中文乱码问题
  96. */
  97. outputStream.write(s.getBytes(charsetName));
  98. }
  99. /**
  100. * Writes a <code>boolean</code> value to the client,
  101. * with no carriage return-line feed (CRLF)
  102. * character at the end.
  103. *
  104. * @param b         the <code>boolean</code> value
  105. *              to send to the client
  106. *
  107. * @exception IOException   if an input or output exception occurred
  108. *
  109. */
  110. public void print(boolean b) throws IOException {
  111. print(b?"true":"false");
  112. }
  113. /**
  114. * Writes a character to the client,
  115. * with no carriage return-line feed (CRLF)
  116. * at the end.
  117. *
  118. * @param c         the character to send to the client
  119. *
  120. * @exception IOException   if an input or output exception occurred
  121. *
  122. */
  123. public void print(char c) throws IOException {
  124. print(String.valueOf(c));
  125. }
  126. /**
  127. *
  128. * Writes an int to the client,
  129. * with no carriage return-line feed (CRLF)
  130. * at the end.
  131. *
  132. * @param i         the int to send to the client
  133. *
  134. * @exception IOException   if an input or output exception occurred
  135. *
  136. */
  137. public void print(int i) throws IOException {
  138. print(String.valueOf(i));
  139. }
  140. /**
  141. *
  142. * Writes a <code>long</code> value to the client,
  143. * with no carriage return-line feed (CRLF) at the end.
  144. *
  145. * @param l         the <code>long</code> value
  146. *              to send to the client
  147. *
  148. * @exception IOException   if an input or output exception
  149. *              occurred
  150. *
  151. */
  152. public void print(long l) throws IOException {
  153. print(String.valueOf(l));
  154. }
  155. /**
  156. *
  157. * Writes a <code>float</code> value to the client,
  158. * with no carriage return-line feed (CRLF) at the end.
  159. *
  160. * @param f         the <code>float</code> value
  161. *              to send to the client
  162. *
  163. * @exception IOException   if an input or output exception occurred
  164. *
  165. *
  166. */
  167. public void print(float f) throws IOException {
  168. print(String.valueOf(f));
  169. }
  170. /**
  171. *
  172. * Writes a <code>double</code> value to the client,
  173. * with no carriage return-line feed (CRLF) at the end.
  174. *
  175. * @param d         the <code>double</code> value
  176. *              to send to the client
  177. *
  178. * @exception IOException   if an input or output exception occurred
  179. *
  180. */
  181. public void print(double d) throws IOException {
  182. print(String.valueOf(d));
  183. }
  184. /**
  185. * Writes a carriage return-line feed (CRLF)
  186. * to the client.
  187. *
  188. *
  189. *
  190. * @exception IOException   if an input or output exception occurred
  191. *
  192. */
  193. public void println() throws IOException {
  194. print("\r\n");
  195. }
  196. /**
  197. * Writes a <code>String</code> to the client,
  198. * followed by a carriage return-line feed (CRLF).
  199. *
  200. *
  201. * @param s         the <code>String</code> to write to the client
  202. *
  203. * @exception IOException   if an input or output exception occurred
  204. *
  205. */
  206. public void println(String s){
  207. println(s, "UTF-8");
  208. }
  209. public void println(String s, String charsetName){
  210. /*
  211. * 解决中文乱码问题
  212. */
  213. try {
  214. print(s,charsetName);
  215. println();
  216. } catch (IOException e) {
  217. throw new RuntimeException(e);
  218. }
  219. }
  220. /**
  221. *
  222. * Writes a <code>boolean</code> value to the client,
  223. * followed by a
  224. * carriage return-line feed (CRLF).
  225. *
  226. *
  227. * @param b         the <code>boolean</code> value
  228. *              to write to the client
  229. *
  230. * @exception IOException   if an input or output exception occurred
  231. *
  232. */
  233. public void println(boolean b) throws IOException {
  234. print(b);
  235. println();
  236. }
  237. /**
  238. *
  239. * Writes a character to the client, followed by a carriage
  240. * return-line feed (CRLF).
  241. *
  242. * @param c         the character to write to the client
  243. *
  244. * @exception IOException   if an input or output exception occurred
  245. *
  246. */
  247. public void println(char c) throws IOException {
  248. print(c);
  249. println();
  250. }
  251. /**
  252. *
  253. * Writes an int to the client, followed by a
  254. * carriage return-line feed (CRLF) character.
  255. *
  256. *
  257. * @param i         the int to write to the client
  258. *
  259. * @exception IOException   if an input or output exception occurred
  260. *
  261. */
  262. public void println(int i) throws IOException {
  263. print(i);
  264. println();
  265. }
  266. /**
  267. *
  268. * Writes a <code>long</code> value to the client, followed by a
  269. * carriage return-line feed (CRLF).
  270. *
  271. *
  272. * @param l         the <code>long</code> value to write to the client
  273. *
  274. * @exception IOException   if an input or output exception occurred
  275. *
  276. */
  277. public void println(long l) throws IOException {
  278. print(l);
  279. println();
  280. }
  281. /**
  282. *
  283. * Writes a <code>float</code> value to the client,
  284. * followed by a carriage return-line feed (CRLF).
  285. *
  286. * @param f         the <code>float</code> value
  287. *              to write to the client
  288. *
  289. *
  290. * @exception IOException   if an input or output exception
  291. *              occurred
  292. *
  293. */
  294. public void println(float f) throws IOException {
  295. print(f);
  296. println();
  297. }
  298. /**
  299. *
  300. * Writes a <code>double</code> value to the client,
  301. * followed by a carriage return-line feed (CRLF).
  302. *
  303. *
  304. * @param d         the <code>double</code> value
  305. *              to write to the client
  306. *
  307. * @exception IOException   if an input or output exception occurred
  308. *
  309. */
  310. public void println(double d) throws IOException {
  311. print(d);
  312. println();
  313. }
  314. /**
  315. * Flushes this output stream and forces any buffered output bytes
  316. * to be written out. The general contract of <code>flush</code> is
  317. * that calling it is an indication that, if any bytes previously
  318. * written have been buffered by the implementation of the output
  319. * stream, such bytes should immediately be written to their
  320. * intended destination.
  321. * <p>
  322. * If the intended destination of this stream is an abstraction provided by
  323. * the underlying operating system, for example a file, then flushing the
  324. * stream guarantees only that bytes previously written to the stream are
  325. * passed to the operating system for writing; it does not guarantee that
  326. * they are actually written to a physical device such as a disk drive.
  327. * <p>
  328. * The <code>flush</code> method of <code>OutputStream</code> does nothing.
  329. *
  330. * @exception  IOException  if an I/O error occurs.
  331. */
  332. public void flush() throws IOException {
  333. outputStream.flush();
  334. }
  335. /**
  336. * Closes this output stream and releases any system resources
  337. * associated with this stream. The general contract of <code>close</code>
  338. * is that it closes the output stream. A closed stream cannot perform
  339. * output operations and cannot be reopened.
  340. * <p>
  341. * The <code>close</code> method of <code>OutputStream</code> does nothing.
  342. *
  343. * @exception  IOException  if an I/O error occurs.
  344. */
  345. public void close() throws IOException {
  346. outputStream.close();
  347. }
  348. /**
  349. * Resets the <code>count</code> field of this byte array output
  350. * stream to zero, so that all currently accumulated output in the
  351. * output stream is discarded. The output stream can be used again,
  352. * reusing the already allocated buffer space.
  353. *
  354. * @see     java.io.ByteArrayInputStream#count
  355. */
  356. public void reset() {
  357. outputStream.reset();
  358. }
  359. public byte[] toByteArray() {
  360. return outputStream.toByteArray();
  361. }
  362. }

在web.xml中配置 PageVisitFilter,当我们访问应用中以.htm,.html,.jsp,.js,.ajax,.css结尾的资源的使用,服务器端就开启http gzip压缩,将压缩后的信息通过http 协议传递给浏览器.

  1. <filter>
  2. <filter-name>Page Visit Filter</filter-name>
  3. <filter-class>com.tyyd.framework.web.PageVisitFilter</filter-class>
  4. </filter>
  5. <filter-mapping>
  6. <filter-name>Page Visit Filter</filter-name>
  7. <url-pattern>/*</url-pattern>
  8. </filter-mapping>

3、AJAX也可以通过这种方式压缩

只需知道ajax请求的后缀添加到下面的代码中即可:

//需要过滤的扩展名:.htm,.html,.jsp,.js,.ajax,.css

String gzippPattern=",.htm,.html,.jsp,.js,.ajax,.css,";