fred-ye / summary

my blog
43 stars 9 forks source link

[Android] HTTP缓存的使用 #50

Open fred-ye opened 9 years ago

fred-ye commented 9 years ago

在做Web的时候,有这么一个体会。当我们第二次开一个网页的速度通常比第一次要快。举个例子,当我们用浏览器打开百度时,第一次打开百度,从浏览器开发者工具中我们可以看到(下面的图片太小了,点击才能看得清) screen shot 2015-07-21 at 9 27 49 pm 对于很多资源,服务器端返回的响应状态码是200。以bd_logo1.png资源为例,我们看它的响应状态: screen shot 2015-07-21 at 9 37 13 pm

但是,当我们再一次访问百度时(刷新页面), 我们发现此时大部份资源的状态码是304. 如下图: screen shot 2015-07-21 at 9 39 37 pm

同样,看我们关注的那个bd_logo1.png资源,其状态 screen shot 2015-07-21 at 9 41 45 pm

比对上面的两次操作。对于第一次操作,浏览器在向服务器请求这个图片资源时,http请求返回的状态码是200,其http request的header中没有太多的信息,其http response的header中有了两个我们比较关心的属性。

ETag:"1ec5-502264e2ae4c0"
Last-Modified:Wed, 03 Sep 2014 10:00:27 GMT

在第二次请求时,其http request的header中添加了两个属性

If-Modified-Since:Wed, 03 Sep 2014 10:00:27 GMT
If-None-Match:"1ec5-502264e2ae4c0"

第二次的请求,http response的header中,有一个 ETag:"1ec5-502264e2ae4c0", 但是并没有Last-Modified属性,同时第二次的http请求返回状态码是304

当服务器返回的状态码是304时,则是告诉客户端,请求的资源没有任何变化,直接从本地缓存中取。

总结一下,对于第一次的http请求,服务器返回的状态码是200, 在返回我们需要的资源的同时会返回两个属性ETagLast-Modified。在第二次请求时,虽说请求的是同一个资源,但会在http请求头中加入两个属性If-Modified-SinceIf-None-Match。其中If-Modified-Since的值便是第一次请求资源时拿到的Last-Modified属性值,If-None-Match的值便是第一次请求资源时拿到的ETag值。当服务器拿到这两个属性后会再次和所请求的资源进行一个匹配,如果请求的资源这两个属性没有任何变化,便会返回一个304状态码给客户端,不会返回资源实体的内容,从而节省带宽,提高响应速度。

在Android程序开发中,偶尔我们也需要利用这个原理。比如,由于某个特定业务需求,我们程序偶尔需要从服务器上的某个路径下载一个文本文件,而这个文本文件中内容变化不是非常频繁,可能几个月变一次,此时我们便可以利用这个机制了。以下给出一段简单的代码:


import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import com.aug.summary.R;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class TestVolleyActivity extends Activity {
    private Button btnSend;
    private static String lastModified;
    private static String eTag;
    private static String date;
    private static final String TAG = "TestVolley";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_volley);
        intView();
    }

    private View.OnClickListener listener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            new Thread() {
                public void run() {
                    try {
                        URL url = new URL("https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/global/img/icons_f0338722.png");
                        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                        if (lastModified != null) {
                            connection.addRequestProperty("If-Modified-Since", lastModified);
                        }
                        if(eTag != null) {
                            connection.addRequestProperty("If-None-Match", eTag);
                        }
                        String responseMessage = connection.getResponseMessage();
                        lastModified = connection.getHeaderField("Last-Modified");
                        eTag = connection.getHeaderField("ETag");
                        Log.i(TAG, "last-modified:" + lastModified);
                        Log.i(TAG, "eTag:" + eTag);
                        Log.i(TAG, connection.getResponseCode() + "  " + connection.getResponseMessage() + "  content length:" + connection.getContentLength());

                    } catch (MalformedURLException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }.start();

        }
    };
    public void intView() {
        btnSend = (Button) findViewById(R.id.btn_send_http_by_volly);
        btnSend.setOnClickListener(listener);
    }

}

第一次点击按钮时Log如下

07-21 10:50:12.320 2075-2198/com.aug.summary I/TestVolley﹕ last-modified:Tue, 23 Jun 2015 08:24:13 GMT 07-21 10:50:12.320 2075-2198/com.aug.summary I/TestVolley﹕ eTag:"37a6-5192b1d838540" 07-21 10:50:12.320 2075-2198/com.aug.summary I/TestVolley﹕ 200 OK content length:14246

第二次点击按钮时Log如下

07-21 10:51:33.837 2075-2611/com.aug.summary I/TestVolley﹕ last-modified:Tue, 23 Jun 2015 08:24:13 GMT 07-21 10:51:33.837 2075-2611/com.aug.summary I/TestVolley﹕ eTag:"37a6-5192b1d838540" 07-21 10:51:33.837 2075-2611/com.aug.summary I/TestVolley﹕ 304 Not Modified content length:0