Java 中如何实现 HTTP 缓存

发布时间:2025-01-19 18:07:11 作者:小樊
来源:亿速云 阅读:108

在 Java 中,可以使用 HttpURLConnection 类或者第三方库如 Apache HttpClient 或者 OkHttp 来实现 HTTP 缓存

  1. 使用 HttpURLConnection 类实现 HTTP 缓存:
import java.io.*;
import java.net.*;
import java.util.*;

public class HttpCache {
    private static final int MAX_CACHE_SIZE = 10 * 1024 * 1024; // 10 MiB
    private Map<String, CacheEntry> cache = new LinkedHashMap<String, CacheEntry>(MAX_CACHE_SIZE, 0.75f, true) {
        protected boolean removeEldestEntry(Map.Entry<String, CacheEntry> eldest) {
            return size() > MAX_CACHE_SIZE;
        }
    };

    public InputStream get(String url) throws IOException {
        CacheEntry entry = cache.get(url);
        if (entry == null || entry.isExpired()) {
            URLConnection connection = new URL(url).openConnection();
            connection.setUseCaches(true);
            connection.connect();

            if (entry == null) {
                entry = new CacheEntry();
            } else {
                entry.revalidate(connection.getExpiration());
            }

            entry.setContentLength((int) connection.getContentLength());
            entry.setContentType(connection.getContentType());
            entry.setLastModified(connection.getLastModified());
            cache.put(url, entry);
        }

        return new BufferedInputStream(new FileInputStream(entry.getFile()));
    }

    private static class CacheEntry implements Serializable {
        private File file;
        private long lastModified;
        private int contentLength;
        private String contentType;
        private transient long expiration;

        public File getFile() {
            return file;
        }

        public void setFile(File file) {
            this.file = file;
        }

        public long getLastModified() {
            return lastModified;
        }

        public void setLastModified(long lastModified) {
            this.lastModified = lastModified;
        }

        public int getContentLength() {
            return contentLength;
        }

        public void setContentLength(int contentLength) {
            this.contentLength = contentLength;
        }

        public String getContentType() {
            return contentType;
        }

        public void setContentType(String contentType) {
            this.contentType = contentType;
        }

        public long getExpiration() {
            return expiration;
        }

        public void revalidate(long currentTime) {
            this.expiration = currentTime + (3600 * 1000); // 1 hour
        }
    }
}
  1. 使用 Apache HttpClient 类实现 HTTP 缓存:

首先,需要添加 Apache HttpClient 依赖到项目中。如果使用 Maven,可以在 pom.xml 文件中添加以下依赖:

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.13</version>
</dependency>

然后,可以使用以下代码实现 HTTP 缓存:

import org.apache.http.*;
import org.apache.http.client.methods.*;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.cache.CacheConfig;
import org.apache.http.impl.client.cache.CachingHttpClientConnectionManager;
import java.io.*;

public class HttpCache {
    private static final int MAX_CACHE_SIZE = 10 * 1024 * 1024; // 10 MiB

    public InputStream get(String url) throws IOException {
        CloseableHttpClient httpClient = createHttpClientWithCache();
        HttpGet httpGet = new HttpGet(url);

        try {
            HttpResponse httpResponse = httpClient.execute(httpGet);
            int statusCode = httpResponse.getStatusLine().getStatusCode();

            if (statusCode == HttpStatus.SC_OK) {
                Header[] headers = httpResponse.getHeaders("Last-Modified");
                long lastModified = -1;
                if (headers != null && headers.length > 0) {
                    lastModified = Long.parseLong(headers[0].getValue());
                }

                File cacheFile = new File(getCacheDirectory(), url.hashCode() + ".dat");
                if (lastModified != -1 && isCacheValid(lastModified, cacheFile)) {
                    return new BufferedInputStream(new FileInputStream(cacheFile));
                }

                HttpEntity httpEntity = httpResponse.getEntity();
                if (httpEntity != null) {
                    File outputFile = new File(getCacheDirectory(), url.hashCode() + ".dat");
                    try (FileOutputStream fos = new FileOutputStream(outputFile)) {
                        byte[] buffer = new byte[1024];
                        int bytesRead;
                        while ((bytesRead = httpEntity.getContent().read(buffer)) != -1) {
                            fos.write(buffer, 0, bytesRead);
                        }
                    }

                    return new BufferedInputStream(new FileInputStream(outputFile));
                }
            }
        } finally {
            httpClient.close();
        }

        throw new IOException("Failed to fetch URL: " + url);
    }

    private CloseableHttpClient createHttpClientWithCache() {
        CachingHttpClientConnectionManager cmcm = new CachingHttpClientConnectionManager();
        cmcm.setMaxTotal(200);
        cmcm.setDefaultMaxPerRoute(20);

        CacheConfig cc = new CacheConfig();
        cc.setMaxSize(MAX_CACHE_SIZE);
        cc.setExpireAfterWrite(3600); // 1 hour
        cc.setMaxSizePolicy(CacheConfig.MaxSizePolicy.MAX_SIZE_PER_ROUTE);

        return HttpClients.custom()
                .setConnectionManager(cmcm)
                .setCacheConfig(cc)
                .build();
    }

    private boolean isCacheValid(long lastModified, File cacheFile) {
        return lastModified == cacheFile.lastModified() && !cacheFile.exists() || System.currentTimeMillis() < cacheFile.lastModified() + (3600 * 1000); // 1 hour
    }

    private File getCacheDirectory() {
        File cacheDir = new File(System.getProperty("java.io.tmpdir"), "http-cache");
        if (!cacheDir.exists()) {
            cacheDir.mkdirs();
        }
        return cacheDir;
    }
}
  1. 使用 OkHttp 类实现 HTTP 缓存:

首先,需要添加 OkHttp 依赖到项目中。如果使用 Maven,可以在 pom.xml 文件中添加以下依赖:

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.9.1</version>
</dependency>

然后,可以使用以下代码实现 HTTP 缓存:

import okhttp3.*;
import java.io.*;
import java.util.concurrent.TimeUnit;

public class HttpCache {
    private static final int MAX_CACHE_SIZE = 10 * 1024 * 1024; // 10 MiB
    private Cache cache;

    public HttpCache() throws IOException {
        File cacheDirectory = new File(System.getProperty("java.io.tmpdir"), "http-cache");
        cache = new Cache(cacheDirectory, MAX_CACHE_SIZE);
    }

    public InputStream get(String url) throws IOException {
        Request request = new Request.Builder()
                .url(url)
                .cacheControl(CacheControl.FORCE_CACHE)
                .build();

        try (Response response = client().newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Unexpected code " + response);
            }

            long currentTime = System.currentTimeMillis();
            long expiration = response.header("Last-Modified") != null ? Long.parseLong(response.header("Last-Modified")) : currentTime + (3600 * 1000); // 1 hour

            File cacheFile = new File(cache.directory(), url.hashCode() + ".dat");
            if (isCacheValid(currentTime, expiration, cacheFile)) {
                return new BufferedInputStream(new FileInputStream(cacheFile));
            }

            ResponseBody responseBody = response.body();
            if (responseBody != null) {
                File outputFile = new File(cache.directory(), url.hashCode() + ".dat");
                try (FileOutputStream fos = new FileOutputStream(outputFile)) {
                    byte[] buffer = new byte[1024];
                    int bytesRead;
                    while ((bytesRead = responseBody.bytes().read(buffer)) != -1) {
                        fos.write(buffer, 0, bytesRead);
                    }
                }
            }
        }

        throw new IOException("Failed to fetch URL: " + url);
    }

    private boolean isCacheValid(long currentTime, long expiration, File cacheFile) {
        return currentTime < expiration && lastModified(cacheFile) == currentTime;
    }

    private long lastModified(File cacheFile) {
        try {
            return cacheFile.lastModified();
        } catch (Exception e) {
            return -1;
        }
    }

    private OkHttpClient client() {
        return new OkHttpClient.Builder()
                .cache(cache)
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .build();
    }
}

这些示例代码展示了如何在 Java 中实现 HTTP 缓存。你可以根据自己的需求进行调整和优化。

推荐阅读:
  1. java中HTTP请求流程是怎么样的
  2. java缓存核心技术的示例分析

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:虚拟化服务器运维有哪些关键技巧

下一篇:服务器运维,VLAN怎样规划

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》