图片加载框架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:
请求头中不含有Cookie:
HttpRequest:
HttpResponse:
这是因为服务端把客户端的用户信息存在了Session域中,如果不带cookie,服务端无法获取到用户信息,被认为是不合法的请求,Server端就不返回响应了(有的Server端也可能出于安全考虑)。
通过发送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表单中:
所以在模拟用户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采用单例模式,只需要初始化一次
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端图片。