关于ETag和Gzip的基本认知和使用

题引:为了提升用户体验,同时减轻服务器压力和降低网络带宽,技术总监和技术经理决定对APP做缓存和压缩处理,包括图片的三级缓存(这里不讨论)和网络请求的数据缓存和压缩
  • ETag的基本认识
  • ETag的基本使用
  • Gzip的基本认识
  • Gzip的基本使用
  • 判读服务器是否返回压缩数据的方式
  • 服务端Nginx配置ETag和Gzip冲突的解决方案
  • Refer
一、ETag的基本认识

以下四篇文章讲解的都是ETag的基本知识:

  1. 客户端HTTP协议缓存的研究
  2. If-Modified-Since & If-None-Match
  3. REST笔记(五):你应该知道的HTTP头——ETag
  4. http协议-缓存统制:etag If-None-Match / Last-Modified If-Modified-Since
二、ETag的基本使用

ETag的使用就Android客户端来说,大概有两个步骤:

  1. Header添加If-None-Match/ETag信息
  2. 执行请求返回响应体后做相应的缓存处理
三、Gzip的基本认识

HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术。大流量的WEB站点常常使用GZIP压缩技术来减少文件大小,减少文件大小有两个明显的好处,一是可以减少存储空间,二是通过网络传输文件时,可以减少传输的时间。

四、Gzip的基本使用

Gzip的基本使用就Android客户端来说,大概有两个步骤:

  1. Header添加Accept-Encoding属性值为gzip
  2. 执行请求返回响应体后做相应的解压处理
附样板代码如下:

1、获取HttpClient

private static DefaultHttpClient getHttpClient() {  
        DefaultHttpClient httpClient = new DefaultHttpClient();  

        // 设置 连接超时时间  
        httpClient.getParams().setParameter(  
                HttpConnectionParams.CONNECTION_TIMEOUT, TIMEOUT_CONNECTION);  
        // 设置 读数据超时时间  
        httpClient.getParams().setParameter(HttpConnectionParams.SO_TIMEOUT,  
                TIMEOUT_SOCKET);  
        // 设置 字符集  
        httpClient.getParams().setParameter("http.protocol.content-charset",  
                UTF_8);  
        return httpClient;  
}  

2、获取HttpPost

private static HttpPost getHttpPost(String url) {  
        HttpPost httpPost = new HttpPost(url);  
        // 设置 请求超时时间  
        httpPost.getParams().setParameter(HttpConnectionParams.SO_TIMEOUT,  
                TIMEOUT_SOCKET);  
        httpPost.setHeader("Connection", "Keep-Alive");  
        httpPost.addHeader("Accept-Encoding", "gzip");  
        return httpPost;  
} 

3、访问网络及解压

public static InputStream http_post_return_byte(String url,  
            Map<String, String> params) throws AppException {  
        DefaultHttpClient httpclient = null;  
        HttpPost post = null;  
        HttpResponse response = null;  
        StringBuilder sb = null;  
        StringEntity stringEntity = null;  
        try {  
            httpclient = getHttpClient();  
            post = getHttpPost(url);  
            sb = new StringBuilder();  
            if (params != null && !params.isEmpty()) {  
                Logger.d("In http_post the url is get here");  
                for (Entry<String, String> entry : params.entrySet()) {  
                    sb.append(entry.getKey())  
                            .append("=")  
                            .append(URLEncoder.encode(entry.getValue(),  
                                    HTTP.UTF_8)).append("&");  
                }  
                sb.deleteCharAt(sb.lastIndexOf("&"));  
                Logger.d("In http_post the url is " + url + " and params is "  
                        + sb.toString());  
                stringEntity = new StringEntity(sb.toString());  
                stringEntity  
                        .setContentType("application/x-www-form-urlencoded");  
                post.setEntity(stringEntity);  
            }  

            response = httpclient.execute(post);  
            int statusCode = response.getStatusLine().getStatusCode();  
            Logger.d("statusCode is " + statusCode);  
            if (statusCode != HttpStatus.SC_OK) {  
                throw AppException.http(statusCode);  
            }  

            InputStream is = response.getEntity().getContent();  

            Header contentEncoding = response  
                    .getFirstHeader("Content-Encoding");  
            if (contentEncoding != null  
                    && contentEncoding.getValue().equalsIgnoreCase("gzip")) {  
                is = new GZIPInputStream(new BufferedInputStream(is));  
            }  
            return is;  

        } catch (ClientProtocolException e) {  
            e.printStackTrace();  
            throw AppException.http(e);  
        } catch (IOException e) {  
            e.printStackTrace();  
            throw AppException.network(e);  
        } finally {  

            /* 
             * if (!post.isAborted()) { 
             *  
             * post.abort(); } httpclient = null; 
             */  

        }  

}  
五、判断网络返回的数据是否经过压缩
  1. 从Http 技术细节上讲,request头中如果有 “Accept-Encoding”,”gzip”,response中就有返回头”Content-Encoding”:”gzip”,因此可以通过判读响应体是否有Content-Encoding属性,并且其值为gzip。
  2. gzip流前两个字节是0x1f8b,因此可通过判断输入流的前两个字节是否为0x1f8b。

附具体代码如下:

private String getJsonStringFromGZIP(HttpResponse response) {
        String jsonString = null;
        try {
            InputStream is = response.getEntity().getContent();
            BufferedInputStream bis = new BufferedInputStream(is);
            bis.mark(2);
            // 取前两个字节
            byte[] header = new byte[2];
            int result = bis.read(header);
            // reset输入流到开始位置
            bis.reset();
            // 判断是否是GZIP格式
            int headerData = getShort(header);
            // Gzip 流 的前两个字节是 0x1f8b
            if (result != -1 && headerData == 0x1f8b) {
                LogUtil.d("HttpTask", " use GZIPInputStream  ");
                is = new GZIPInputStream(bis);
            } else {
                LogUtil.d("HttpTask", " not use GZIPInputStream");
                is = bis;
            }
            InputStreamReader reader = new InputStreamReader(is, "utf-8");
            char[] data = new char[100];
            int readSize;
            StringBuffer sb = new StringBuffer();
            while ((readSize = reader.read(data)) > 0) {
                sb.append(data, 0, readSize);
            }
            jsonString = sb.toString();
            bis.close();
            reader.close();
        } catch (Exception e) {
            LogUtil.e("HttpTask", e.toString(),e);
        }

        LogUtil.d("HttpTask", "getJsonStringFromGZIP net output : " + jsonString );
        return jsonString;
    }

    private int getShort(byte[] data) {
        return (int)((data[0]<<8) | data[1]&0xFF);
    }
六、服务端Nginx配置ETag和Gzip冲突的解决方案

以下三篇文章都涉及到ETag和Gzip冲突的解决方案:

  1. nginx开启gzip模块后ETAG丢失
  2. nginx - missing etag when gzip is used
  3. Nginx如何开启ETag,提高访问速度
七、Refer
  1. Android中使用gzip传递数据
  2. Android开发中网络请求的压缩 ── GZip的使用
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值