Android ImageLoader获取Http请求需带Cookie图片

前言

图片加载框架ImageLoader有缓存,获取图片过程中显示不同图片,异步加载等很多便利的功能。通过ImageLoader加载Server端图片十分方便,通过HTTP GET获取时,有时需要client提供一些必要的信息和session才能正常获取。
获取的过程也十分简单,在初始化完成ImageLoader之后,调用方法即可,如下:

ImageLoader.getInstance().displayImage(imageUri,
                    (ImageView) layout.findViewById(R.id.imageItem),
                    options, animateFirstListener);

但是有些情况下需要client提供一些参数和session,server端通过处理这些参数得到client所需的图片,然后才能正常返回响应图片。
在含有session_id的http请求,服务器返回200:
HttpRequest:
Android ImageLoader获取Http请求需带Cookie图片_第1张图片

HttpResponse:
Android ImageLoader获取Http请求需带Cookie图片_第2张图片

请求头中不含有Cookie:
HttpRequest:
Android ImageLoader获取Http请求需带Cookie图片_第3张图片
HttpResponse:
Android ImageLoader获取Http请求需带Cookie图片_第4张图片

这是因为服务端把客户端的用户信息存在了Session域中,如果不带cookie,服务端无法获取到用户信息,被认为是不合法的请求,Server端就不返回响应了(有的Server端也可能出于安全考虑)。

如何获取session_id

通过发送httprequest与服务端建立通讯,通过Sever返回的httpresponse的header获取session_id有时候是可行的,但是有些情况下Server端并不保留返回给Client端的Session或者这个Session在服务端存在的时间非常短暂,导致Client端拿着这个Session_id获取图片的时候服务端验证不通过,拒绝响应,这些情况下我们需要模拟一次用户登录,登录成功后服务器会记住用户的session,通过这个session_id就可以正常的获取Server端图片。

如何模拟用户登录

通过http post或者get请求,把用户信息传递给Server端,模拟用户登入,但是有些网站为了防止csrf攻击,往往需要用户登入过程提供csrf_token,这个token值一般是用户在访问登入页面时由Server端生成,返回给webclient端登入页面的,一般作为一个隐藏域存在form表单中:

class="oe_login_form" role="form" action="/web/login" method="post" onsubmit="this.action = this.action + location.hash"> "csrf_token" value="c091f253d41f65f79ed3d6f21f255683d5efa7eao1476672733" type="hidden"> .....

所以在模拟用户login时一般要抓取登入页面的csrf_token。
下面是一串Androidclient端的代码:

    private void getSessionInfo()
    {
        HttpHelper.get("/web?db="+Global.DB, new AsyncHttpResponseHandler() {
            @Override
            public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
                HtmlElementUtil.getHeaderSession(headers);
                String res = new String(responseBody);
                List result = HtmlElementUtil.match(res,"input","value");
                if(result == null || result.size() == 0)
                {
                    return;//如果session没有过期那么就继续使用
                }
                RequestParams params = new RequestParams();
                params.add("csrf_token",result.get(0).replace("/","").replace("\"",""));
                params.add("db","pos");
                params.add("login","admin");
                params.add("password","admin");
                params.add("redirect","");
                HttpHelper.post("/web/login",params,new AsyncHttpResponseHandler(){
                    @Override
                    public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
                        HtmlElementUtil.getHeaderSession(headers);
                    }

                    @Override
                    public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
                        String res = new String(responseBody);
                    }
                });
            }

            @Override
            public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {

            }
        });
    }

注:
HttpHelper是一个基于async-http的工具类。
web/db是服务端的数据库选择页面,服务端会通过临时session判断是否选择数据库,如果没有选择,会强制跳转到数据库选择页面。
跳转到登录页面之后,HtmlElementUtil.match(res,”input”,”value”)方法时自定义方法大致就是正则匹配所有的input标签,获取所有的value值(是一个list),通过value(list中包含csrf_token的值)便可以获取csrf_token。登入成功后通过HtmlElementUtil.getHeaderSession(headers)静态方法,从Server返回的Header数组中Cookie:session_id键值对获取session_id。

自定义ImageLoader请求头

//ImageLoader的初始化方法,ImageLoader采用单例模式,只需要初始化一次
private void InitiateImgLoaderOpt() {
        ImageLoaderConfiguration.Builder config = new ImageLoaderConfiguration.Builder(getApplicationContext());
        config.threadPriority(Thread.NORM_PRIORITY - 2);
        config.denyCacheImageMultipleSizesInMemory();
        config.diskCacheFileNameGenerator(new Md5FileNameGenerator());
        config.diskCacheSize(50 * 1024 * 1024); // 50 MiB
        config.tasksProcessingOrder(QueueProcessingType.LIFO);
        config.writeDebugLogs(); // Remove for release app
        config.imageDownloader(new ImageDownloader(this));
        // Initialize ImageLoader with configuration.
        ImageLoader.getInstance().init(config.build());
    }

public class ImageDownloader extends BaseImageDownloader {
    public ImageDownloader(Context context) {
        super(context);
    }
//ImageLoader图片加载httprequest设置方法
    @Override
    protected HttpURLConnection createConnection(String url, Object extra) throws IOException {
        // Super...
        HttpURLConnection connection = super.createConnection(url, extra);
        connection.setRequestProperty("Cookie", Global.SESSION_ID);
        connection.setRequestProperty("Connection", "keep-alive");
        return connection;
    }
}

//此代码设置Android view视图中的图片,animateFirstListener是加载状态的监听器
ImageLoader.getInstance().displayImage(imageUri,
                    (ImageView) layout.findViewById(R.id.imageItem),
                    options, animateFirstListener);

//通过复写监听器类的onLoadingStarted,onLoadingFailed,onLoadingComplete,onLoadingCancelled方法设置对应显示的图片
 private static class AnimateFirstDisplayListener extends SimpleImageLoadingListener {

        static final List displayedImages = Collections.synchronizedList(new LinkedList());

        @Override
        public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
            if (loadedImage != null) {
                ImageView imageView = (ImageView) view;
                boolean firstDisplay = !displayedImages.contains(imageUri);
                if (firstDisplay) {
                    FadeInBitmapDisplayer.animate(imageView, 500);
                    displayedImages.add(imageUri);
                }
            }
        }
        @Override
        public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
            String re = failReason.toString();
        }
    }

其中的自定义类ImageDownloader就是ImageLoader加载网络图片的http请求的构造器,此类需要继承BaseImageDownloader。通过复写基类的createConnection方法,在方法体重创建HttpURLConnection(图片请求连接)设置获取到的Cookie(Session_id),便可以正常加载Server端图片。

你可能感兴趣的:(Android)