当前位置: > > > JAVA - 实现服务端gzip数据的解析

JAVA - 实现服务端gzip数据的解析

我原来写过一篇关于 gzip 压缩与解析文章:Swift - 使用gzip压缩NSData数据(附:请求时将JSON数据进行压缩)。当时客户端是 iOS 平台,而服务端使用的 PHP
样例中客户端先将 json 数据通过 gzip 压缩后发送给服务端。服务端收到数据后先解压缩,再解析数据。最后将解析的数据又返回给客户端。客户端把返回的数据打印出来(如下图)。数据等正确输出说明整个压缩解压的流程是没问题的。
有网友问了,如果我的服务端是用 JAVA 写的,该怎么办。本文我就介绍下 JAVA 如何解压 gzip 数据。

一、创建处理gzip的过滤器
要实现 gzip 解压,我们先要创建个过滤器(servlet Filter),用来对所有的 request 请求进行处理。这样不管我们服务端使用哪种web框架都可以很好地适配。
1,GzipRequestWrapper.java
继承自 HttpServletRequestWrapper,其作用就是判断这个 request 的内容是否使用 gzip 压缩了。如果是压缩的,则对其进行解压。
package filter;  
  
import java.io.IOException;  
import java.util.zip.GZIPInputStream;  
import javax.servlet.ServletInputStream;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletRequestWrapper;  
  
public class GzipRequestWrapper extends HttpServletRequestWrapper {  

    private HttpServletRequest request;  
  
    public GzipRequestWrapper(HttpServletRequest request) {  
        super(request);  
        this.request = request;  
    }  
  
    @Override  
    public ServletInputStream getInputStream() throws IOException {  
        ServletInputStream stream = request.getInputStream();  
        String contentEncoding = request.getHeader("Content-Encoding");  
        // 如果对内容进行了压缩,则解压  
        if (null != contentEncoding && contentEncoding.indexOf("gzip") != -1) {  
            try {  
                final GZIPInputStream gzipInputStream = new GZIPInputStream(  
                        stream);  
  
                ServletInputStream newStream = new ServletInputStream() {  
  
                    @Override  
                    public int read() throws IOException {  
                        return gzipInputStream.read();  
                    }  
                };  
                return newStream;  
            } catch (Exception e) {  
                System.out.print("ungzip content fail." + e);  
            }  
        }  
        return stream;  
    }  
} 

2,GzipFilter.java
过滤器类。作用是将请求交由上面的 GzipRequestWrapper 来处理。
package filter;  
  
import java.io.IOException;  
import javax.servlet.Filter;  
import javax.servlet.FilterChain;  
import javax.servlet.FilterConfig;  
import javax.servlet.ServletException;  
import javax.servlet.ServletRequest;  
import javax.servlet.ServletResponse;  
import javax.servlet.http.HttpServletRequest;  
  
/** 
 * 如果请求消息中包含gzip压缩数据,则进行解压 
 */  
public class GzipFilter implements Filter {  
  
    public void init(FilterConfig filterConfig) throws ServletException {  
    }  

    public void doFilter(ServletRequest request, ServletResponse response,  
            FilterChain chain) throws IOException, ServletException {  
        chain.doFilter(new GzipRequestWrapper((HttpServletRequest) request), response);  
    }  
  
    public void destroy() {  
    }  
} 

3,web.xml配置
上面过滤器相关类创建完毕后,我们还需要在 web.xml 对其进行配置。这样过滤器才能生效。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
	xmlns="http://java.sun.com/xml/ns/javaee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  <filter>  
    <filter-name>GzipFilter</filter-name>  
    <filter-class>filter.GzipFilter</filter-class>  
  </filter>  
  <filter-mapping>
    <filter-name>GzipFilter</filter-name>
    <url-pattern>*.action</url-pattern>
  </filter-mapping>  
  <filter-mapping>
    <filter-name>GzipFilter</filter-name>
    <url-pattern>*.jsp</url-pattern>
  </filter-mapping>
</web-app>

二、测试样例
JAVA 作为服务端的话,客户端可以将数据提交到 jsp 页面、sevelet 或是 action 中。这里我用 jsp 作为演示,其他两个同理。毕竟过滤器配好以后这个解压处理是通用的。
1,客户端
这个同前文一样,完全没动。只不过将请求地址改成了 jsp 页面地址。
let params:[String : Any] = [
    "name": "hangge.com",
    "books": ["Swift","Objective-C","PHP"],
    "bar": [
        "baz": "qux"
    ]
]

let url = "http://192.168.1.112:8080/test/post.jsp"
Alamofire.request(url, method: .post, parameters: params, encoding: JSONGzipEncoding.default)
    .responseString { response in
        print(response.result.value!)
    }

2,服务端(post.jsp)
我们将收到的数据转成字符串,并输出到页面上(实际上就是返回给客户端)。
<%@ page language="java" import="java.io.*" pageEncoding="utf-8"%>
<%
byte[] bytes = new byte[1024 * 1024]; 
InputStream is = request.getInputStream(); 
 
int nRead = 1; 
int nTotalRead = 0; 
while (nRead > 0) { 
    nRead = is.read(bytes, nTotalRead, bytes.length - nTotalRead); 
    if (nRead > 0) 
        nTotalRead = nTotalRead + nRead; 
} 
String str = new String(bytes, 0, nTotalRead, "utf-8"); 
 
out.print("服务端收到数据:"+str);
%>

3,客户端将返回数据打印出来
可以看到数据正确打印出来,说明服务端 gzip 数据解压是成功的。

4,源码下载: test(java).zip
评论0