加载https路径图片


本文转载至:http://blog.csdn.net/Alpha58/article/details/61934543



前言

Glide默认加载http或者通过CA认证了的https图片都是没问题的,但是当加载自签名的https图片的时候就会报如下错误(证书路径验证异常)。 
这里写图片描述

一,原理

对于加载自签名的https图片,我们需要通过GlideModule来进行网络请求库的定制。如果你使用的是OkHttp网络请求库,则需要在app的build.gradle 中添加如下依赖:

compile 'com.github.bumptech.glide:okhttp-integration:1.4.0@aar'
  • 1

使用的是Volley网络请求库,则添加依赖为:

compile 'com.github.bumptech.glide:volley-integration:1.3.1@aar'
  • 1

这里主要讲使用OkHttp网络请求库的时候如何通过GlideModule来定制我们的Glide。 
通过添加的依赖源码其中一个类OkHttpGlideModule 可以看出,


import android.content.Context;

import com.alpha58.okhttps.utils.HTTPSUtils;
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.module.GlideModule;

import java.io.InputStream;

/**
 * A {@link GlideModule} implementation to replace Glide's default
 * {@link java.net.HttpURLConnection} based {@link com.bumptech.glide.load.model.ModelLoader} with an OkHttp based
 * {@link com.bumptech.glide.load.model.ModelLoader}.
 *
 * <p>
 *     If you're using gradle, you can include this module simply by depending on the aar, the module will be merged
 *     in by manifest merger. For other build systems or for more more information, see
 *     {@link GlideModule}.
 * </p>
 */
public class OkHttpGlideModule implements GlideModule {
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        // Do nothing.
    }

    @Override
    public void registerComponents(Context context, Glide glide) {
        glide.register(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());
    }
}

源码是通过自定义一个类OkHttpGlideModule实现GlideModule,实现该类主要有2个方法: 
applyOptions方法主要是处理图片质量,缓存等。 
registerComponents方法主要是改变Glide的网络栈,让它能从自签名HTTPS服务器接收连接和图片。 
我们看到在registerComponents方法中new OkHttpUrlLoader.Factory()方法创建了一个okhttpclient对象,点进去看见还有一个相同的带参数的方法

/**
         * Constructor for a new Factory that runs requests using given client.
         */
        public Factory(OkHttpClient client) {
            this.client = client;
        }

这里可以传入一个我们自己的okhttpclient对象,所以如果将我们已经通过认证的okhttpclient传进来替换这个对象就可以解决。

二,解决步骤(非常简单):

1、在build.gradle中添加依赖:

compile 'com.squareup.okhttp3:okhttp:3.6.0'
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'com.github.bumptech.glide:okhttp-integration:1.4.0@aar'

2、拷贝’com.github.bumptech.glide:okhttp-integration:1.4.0@aar’里面3个类OkHttpGlideModule ,OkHttpUrlLoader,OkHttpStreamFetcher到项目中(三个类源码,文章末尾贴出)

注意:OkHttpGlideModule 类的registerComponents方法需要传入已经通过认证的okhttpclient进来替换。如何配置通过认证的okhttpclient看我的另一篇文章:Android使用OkHttp请求自签名的https网站

3、删除在build.gradle中的依赖:

compile 'com.github.bumptech.glide:okhttp-integration:1.4.0@aar'
  • 1

4、在AndroidManifest中配置刚刚拷贝过来的OkHttpGlideModule。

<!--配置glide加载https所需要的GlideModule-->
        <meta-data
            android:name="com.alpha58.okhttps.https.OkHttpGlideModule"
            android:value="GlideModule"/>
  • 1
  • 2
  • 3
  • 4

好了,这个时候我们用Glide就可以将自签名的https图片加载出来啦!

public void getHttpsImg(View view) {
        //自签名https图片链接 (如果链接失效,自行到12306网站找图片)
        String url = "https://travel.12306.cn/imgs/resources/uploadfiles/images/a9b9c76d-36ba-4e4a-8e02-9e6a1a991da0_news_W540_H300.jpg";
        Glide.with(this)
                .load(url)
                .asBitmap()
                .into(mIv_img);
    }

贴上三个类源码,分别如下:

OkHttpGlideModule类:

package com.alpha58.okhttps.https;

import android.content.Context;

import com.alpha58.okhttps.utils.HTTPSUtils;
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.module.GlideModule;

import java.io.InputStream;

/**
 * A {@link GlideModule} implementation to replace Glide's default
 * {@link java.net.HttpURLConnection} based {@link com.bumptech.glide.load.model.ModelLoader} with an OkHttp based
 * {@link com.bumptech.glide.load.model.ModelLoader}.
 *
 * <p>
 *     If you're using gradle, you can include this module simply by depending on the aar, the module will be merged
 *     in by manifest merger. For other build systems or for more more information, see
 *     {@link GlideModule}.
 * </p>
 */
public class OkHttpGlideModule implements GlideModule {
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        // Do nothing.
    }

    @Override
    public void registerComponents(Context context, Glide glide) {
    //注意:new HTTPSUtils(context).getInstance()为已经通过认证的okhttpclient
        glide.register(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(new HTTPSUtils(context).getInstance()));
    }
}



OkHttpUrlLoader类:

package com.alpha58.okhttps.https;

import android.content.Context;

import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.model.GenericLoaderFactory;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.ModelLoader;
import com.bumptech.glide.load.model.ModelLoaderFactory;

import java.io.InputStream;

import okhttp3.OkHttpClient;

/**
 * author           Alpha58
 * time             2017/1/5 22:57
 * desc             ${TODO}
 * <p>
 * upDateAuthor     $Author$
 * upDate           $Date$
 * upDateDesc       ${TODO}
 */
public class OkHttpUrlLoader implements ModelLoader<GlideUrl, InputStream> {

    /**
     * The default factory for {@link OkHttpUrlLoader}s.
     */
    public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {
        private static volatile OkHttpClient internalClient;
        private                 OkHttpClient client;

        private static OkHttpClient getInternalClient() {
            if (internalClient == null) {
                synchronized (Factory.class) {
                    if (internalClient == null) {
                        internalClient = new OkHttpClient();
                    }
                }
            }
            return internalClient;
        }

        /**
         * Constructor for a new Factory that runs requests using a static singleton client.
         */
        public Factory() {
            this(getInternalClient());
        }

        /**
         * Constructor for a new Factory that runs requests using given client.
         */
        public Factory(OkHttpClient client) {
            this.client = client;
        }

        @Override
        public ModelLoader<GlideUrl, InputStream> build(Context context, GenericLoaderFactory factories) {
            return new OkHttpUrlLoader(client);
        }

        @Override
        public void teardown() {
            // Do nothing, this instance doesn't own the client.
        }
    }

    private final OkHttpClient client;

    public OkHttpUrlLoader(OkHttpClient client) {
        this.client = client;
    }

    @Override
    public DataFetcher<InputStream> getResourceFetcher(GlideUrl model, int width, int height) {
        return new OkHttpStreamFetcher(client, model);
    }
}
  • 1

import com.bumptech.glide.Priority;
import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.util.ContentLengthInputStream;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;


/**
 * Fetches an {@link InputStream} using the okhttp library.
 */
public class OkHttpStreamFetcher implements DataFetcher<InputStream> {
    private final OkHttpClient client;
    private final GlideUrl     url;
    private       InputStream  stream;
    private       ResponseBody responseBody;

    public OkHttpStreamFetcher(OkHttpClient client, GlideUrl url) {
        this.client = client;
        this.url = url;
    }

    @Override
    public InputStream loadData(Priority priority) throws Exception {
        Request.Builder requestBuilder = new Request.Builder()
                .url(url.toStringUrl());

        for (Map.Entry<String, String> headerEntry : url.getHeaders().entrySet()) {
            String key = headerEntry.getKey();
            requestBuilder.addHeader(key, headerEntry.getValue());
        }

        Request request = requestBuilder.build();

        Response response = client.newCall(request).execute();
        responseBody = response.body();
        if (!response.isSuccessful()) {
            throw new IOException("Request failed with code: " + response.code());
        }

        long contentLength = responseBody.contentLength();
        stream = ContentLengthInputStream.obtain(responseBody.byteStream(), contentLength);
        return stream;
    }

    @Override
    public void cleanup() {
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException e) {
                // Ignored
            }
        }
        if (responseBody != null) {
            responseBody.close();
        }
    }

    @Override
    public String getId() {
        return url.getCacheKey();
    }

    @Override
    public void cancel() {
        // TODO: call cancel on the client when this method is called on a background thread. See #257
    }
}

Demo地址:https://github.com/Alpha58/okhttps 
参考文章:Glide — Customize Glide with Modules

### 回答1: c路径加载显示图片是一种常见的操作,可以通过编程实现。所谓c路径,是指图片所在文件的路径,可以是本地计算机的文件路径,也可以是网络上的图片路径。 在编程中,可以使用一些图像处理库,如OpenCV、PIL、matplotlib等,来加载并显示图片。具体步骤如下: 1. 首先,需要导入相关的图像处理库。比如使用OpenCV库可以通过以下代码导入: import cv2 2. 在加载图片前,需要提供图片路径路径可以是本地文件路径,如:"C:/images/image.jpg",也可以是网络图片路径,如:"https://www.example.com/image.jpg"。 在使用OpenCV库加载本地图片时,可以使用以下代码: image = cv2.imread("C:/images/image.jpg") 若要加载网络图片,可以使用以下代码: import urllib.request import numpy as np response = urllib.request.urlopen("https://www.example.com/image.jpg") image = np.asarray(bytearray(response.read()), dtype="uint8") image = cv2.imdecode(image, cv2.IMREAD_COLOR) 3. 图片加载完成后,可以使用图像处理库提供的显示函数来显示图片。例如,使用OpenCV库的imshow函数可以显示图片: cv2.imshow("Image", image) 4. 最后,为了能够显示图片,需要调用窗口的等待键盘输入函数,如使用OpenCV库的waitKey函数: cv2.waitKey(0) 以上就是使用c路径加载显示图片的基本步骤。值得注意的是,不同的图像处理库可能会有略微不同的函数和操作,但总体思路是相似的。 ### 回答2: c 路径加载显示图片是指在编程中通过给定的路径,可以从该路径中找到相应的图片文件,并将其加载并显示出来。 在C语言中,可以使用很多库来实现c路径加载显示图片的功能,常用的有SDL图形库和OpenCV库。 使用SDL图形库可以通过以下步骤实现c路径加载显示图片: 1. 引入SDL图形库的头文件。 #include <SDL.h> 2. 初始化SDL。 SDL_Init(SDL_INIT_VIDEO); 3. 创建一个SDL窗口。 SDL_Window* window = SDL_CreateWindow("Image Viewer", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_SHOWN); 4. 创建一个SDL渲染器。 SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0); 5. 加载图片文件并创建一个纹理。 SDL_Surface* surface = SDL_LoadBMP(path); // 加载图片文件 SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface); 6. 清空渲染器并将纹理渲染到窗口上。 SDL_RenderClear(renderer); SDL_RenderCopy(renderer, texture, NULL, NULL); SDL_RenderPresent(renderer); 7. 释放资源并关闭SDL。 SDL_DestroyTexture(texture); SDL_FreeSurface(surface); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); 这样,就可以在c语言中通过给定的路径加载并显示出指定的图片文件了。 另外,如果使用OpenCV库,可以使用cv::imshow()函数来加载和显示图片,代码如下: #include <opencv2/opencv.hpp> int main() { cv::Mat image = cv::imread(path); // 加载图片文件 cv::imshow("Image Viewer", image); // 显示图片 cv::waitKey(0); // 等待按键输入 return 0; } 以上就是c路径加载显示图片的简单实现方法。 ### 回答3: c路径加载显示图片是指通过在HTML或CSS代码中使用绝对或相对路径加载并显示图片路径是用来告诉浏览器图片所在的位置。在使用c路径加载显示图片时,我们需要遵循一定的规则和格式。 绝对路径是从网站的根目录开始描述图片地址的路径,它包含完整的URL,包括协议、域名和路径。例如,如果图片的绝对路径是"http://example.com/images/pic.jpg",我们可以在HTML代码中使用<img>标签来加载显示图片:<img src="http://example.com/images/pic.jpg" alt="图片描述"> 相对路径是从当前文件所在的位置开始描述图片地址的路径,它省略了协议和域名信息。相对路径可以分为两种:相对当前文件的相对路径和相对网站根目录的相对路径。 相对当前文件的相对路径通过引用图片所在文件夹的路径来简化图片地址。例如,如果当前文件所在的路径是"http://example.com/images/index.html",而图片存放在同一文件夹下,我们可以在HTML代码中使用<img>标签来加载显示图片:<img src="pic.jpg" alt="图片描述"> 相对网站根目录的相对路径通过引用从根目录到图片所在文件夹的路径来简化图片地址。例如,如果图片存放在根目录下的images文件夹中,我们可以在HTML代码中使用<img>标签来加载显示图片:<img src="/images/pic.jpg" alt="图片描述"> 无论是绝对路径还是相对路径,我们都可以使用<img>标签的src属性来指定图片路径,并使用alt属性给图片添加描述。这样,当浏览器无法加载图片时,将会显示该描述文字。 在使用c路径加载显示图片时,我们需要确保图片文件的格式正确,路径与文件的位置对应,以及文件名大小写的一致性。这样才能保证图片能够正确加载和显示。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值