本文目录导读:

- 方案一:Service Worker + Cache API(推荐,PWA方案)
- 方案二:本地存储(localStorage)+ PHP动态生成
- 方案三:IndexedDB + PHP API
- 方案四:PHP生成静态缓存文件
- 最佳实践建议
- 注意事项
在PHP项目中实现离线缓存,通常需要结合 Service Worker(PWA技术) 和 本地存储 来实现,PHP本身是服务端语言,所以离线缓存的关键在于前端。
以下是几种主流的实现方案,按推荐程度排序:
Service Worker + Cache API(推荐,PWA方案)
这是目前最成熟、功能最强大的离线缓存方案,适用于PHP构建的Web应用。
实现步骤:
在PHP页面中注册Service Worker
<!-- index.php -->
<!DOCTYPE html>
<html>
<head>离线缓存示例</title>
</head>
<body>
<h1>欢迎访问我们的网站</h1>
<p><?php echo date('Y-m-d H:i:s'); ?></p>
<script>
// 注册 Service Worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(function(registration) {
console.log('Service Worker 注册成功');
})
.catch(function(error) {
console.log('Service Worker 注册失败: ', error);
});
}
</script>
</body>
</html>
创建 Service Worker 文件(sw.js)
// sw.js - 必须放在网站根目录或指定路径
const CACHE_NAME = 'my-cache-v1';
// 需要缓存的资源列表
const urlsToCache = [
'/',
'/index.php',
'/css/main.css',
'/js/main.js',
'/images/logo.png',
'/api/data.json' // PHP API接口
];
// 安装阶段 - 缓存资源
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => {
console.log('打开缓存');
return cache.addAll(urlsToCache);
})
.then(() => self.skipWaiting())
);
});
// 激活阶段 - 清理旧缓存
self.addEventListener('activate', event => {
const cacheWhitelist = [CACHE_NAME];
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheWhitelist.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
})
);
})
);
});
// 拦截请求 - 从缓存获取或网络请求
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
// 如果缓存中有,直接返回
if (response) {
return response;
}
// 缓存中没有,发起网络请求
return fetch(event.request)
.then(response => {
// 检查是否是有效响应
if (!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// 克隆响应(因为流只能使用一次)
const responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(cache => {
cache.put(event.request, responseToCache);
});
return response;
})
.catch(() => {
// 网络请求失败,返回离线页面
return caches.match('/offline.php');
});
})
);
});
PHP离线页面
<!-- offline.php -->
<!DOCTYPE html>
<html>
<head>离线模式</title>
<style>
body { font-family: Arial; text-align: center; padding: 50px; }
.offline-icon { font-size: 80px; margin-bottom: 20px; }
</style>
</head>
<body>
<div class="offline-icon">📡</div>
<h1>您已离线</h1>
<p>当前网络不可用,部分内容可能无法显示。</p>
<p>缓存的页面和资源仍然可以访问。</p>
<button onclick="location.reload()">重新连接</button>
</body>
</html>
缓存策略选择:
// 1. 缓存优先(适合静态资源)
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
// 2. 网络优先(适合实时数据)
event.respondWith(
fetch(event.request)
.then(response => {
// 更新缓存
const responseClone = response.clone();
caches.open(CACHE_NAME).then(cache => {
cache.put(event.request, responseClone);
});
return response;
})
.catch(() => caches.match(event.request))
);
// 3. 网络和缓存同时(适合动态内容)
event.respondWith(
Promise.race([
fetch(event.request),
new Promise(resolve => {
setTimeout(() => resolve(caches.match(event.request)), 300);
})
])
);
本地存储(localStorage)+ PHP动态生成
适用于小规模数据缓存,比如用户设置、配置信息等。
<?php
// php/generate_config.php
header('Content-Type: application/json');
$config = [
'theme' => 'dark',
'language' => 'zh-CN',
'api_endpoint' => '/api/v1/',
'debug_mode' => false,
'updated_at' => date('Y-m-d H:i:s')
];
echo json_encode($config);
?>
// JavaScript端
// 从PHP获取配置并缓存
function loadConfig() {
const cachedConfig = localStorage.getItem('app_config');
const cachedTime = localStorage.getItem('config_time');
// 检查缓存是否过期(例如24小时)
if (cachedConfig && cachedTime) {
const now = new Date().getTime();
const twentyFourHours = 24 * 60 * 60 * 1000;
if (now - parseInt(cachedTime) < twentyFourHours) {
return JSON.parse(cachedConfig);
}
}
// 从服务器获取最新配置
return fetch('/php/generate_config.php')
.then(response => response.json())
.then(config => {
localStorage.setItem('app_config', JSON.stringify(config));
localStorage.setItem('config_time', new Date().getTime().toString());
return config;
});
}
// 使用缓存的配置
loadConfig().then(config => {
console.log('使用配置:', config);
document.body.className = config.theme;
});
IndexedDB + PHP API
适用于大量结构化数据的离线缓存。
<?php
// api/products.php
header('Content-Type: application/json');
// 模拟数据库查询
$products = [
['id' => 1, 'name' => '产品A', 'price' => 99.90],
['id' => 2, 'name' => '产品B', 'price' => 149.90],
['id' => 3, 'name' => '产品C', 'price' => 199.90],
];
echo json_encode($products);
?>
// 使用 IndexedDB 缓存
class ProductCache {
constructor() {
this.dbName = 'productDB';
this.dbVersion = 1;
this.db = null;
}
async openDB() {
return new Promise((resolve, reject) => {
const request = indexedDB.open(this.dbName, this.dbVersion);
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains('products')) {
const store = db.createObjectStore('products', { keyPath: 'id' });
store.createIndex('name', 'name', { unique: false });
}
};
request.onsuccess = (event) => {
this.db = event.target.result;
resolve(this.db);
};
request.onerror = (event) => {
reject('数据库打开失败');
};
});
}
async cacheProducts(products) {
await this.openDB();
const transaction = this.db.transaction(['products'], 'readwrite');
const store = transaction.objectStore('products');
products.forEach(product => {
store.put(product);
});
return new Promise((resolve, reject) => {
transaction.oncomplete = () => resolve();
transaction.onerror = () => reject('缓存失败');
});
}
async getCachedProducts() {
await this.openDB();
const transaction = this.db.transaction(['products'], 'readonly');
const store = transaction.objectStore('products');
const request = store.getAll();
return new Promise((resolve, reject) => {
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject('读取失败');
});
}
}
// 使用示例
const productCache = new ProductCache();
// 缓存数据
function fetchAndCacheProducts() {
fetch('/api/products.php')
.then(response => response.json())
.then(products => {
productCache.cacheProducts(products);
});
}
// 优先使用缓存,再更新
async function getProducts() {
let products = await productCache.getCachedProducts();
if (products.length === 0) {
const response = await fetch('/api/products.php');
products = await response.json();
await productCache.cacheProducts(products);
}
return products;
}
PHP生成静态缓存文件
不经常变化的PHP页面。
<?php
// cache_manager.php
class StaticCache {
private $cacheDir = './cache/';
private $cacheTime = 3600; // 1小时
public function getCache($key) {
$cacheFile = $this->cacheDir . md5($key) . '.cache';
if (file_exists($cacheFile) && (time() - filemtime($cacheFile)) < $this->cacheTime) {
return file_get_contents($cacheFile);
}
return false;
}
public function setCache($key, $content) {
if (!is_dir($this->cacheDir)) {
mkdir($this->cacheDir, 0777, true);
}
$cacheFile = $this->cacheDir . md5($key) . '.cache';
file_put_contents($cacheFile, $content);
}
public function generatePageCache($pageUrl) {
$cache = new StaticCache();
// 检查是否有缓存
$cachedContent = $cache->getCache($pageUrl);
if ($cachedContent !== false) {
echo $cachedContent;
exit;
}
// 开始输出缓冲
ob_start();
// 页面PHP代码...
echo "<h1>动态生成的页面</h1>";
echo "<p>生成时间: " . date('Y-m-d H:i:s') . "</p>";
// 获取页面内容并缓存
$content = ob_get_clean();
$cache->setCache($pageUrl, $content);
echo $content;
}
}
// 使用
$pageCache = new StaticCache();
$pageCache->generatePageCache($_SERVER['REQUEST_URI']);
?>
最佳实践建议
-
选择合适的缓存策略:
- 静态资源(CSS/JS/图片):
Cache First - API数据:
Network First或Stale While Revalidate - 配置信息:使用
localStorage缓存
- 静态资源(CSS/JS/图片):
-
定期更新缓存:
// 在sw.js中定期检查更新 setInterval(() => { caches.open(CACHE_NAME).then(cache => { // 检查并更新所有缓存资源 }); }, 3600000); // 每小时更新一次 -
处理缓存版本:
// 使用版本号控制缓存 const CACHE_NAME = 'my-cache-v' + new Date().getTime();
-
结合PHP生成Service Worker:
<?php // sw.php - 动态生成Service Worker header('Service-Worker-Allowed: /'); header('Content-Type: application/javascript'); header('Cache-Control: no-cache'); $version = '1.0.' . date('Ymd'); ?> const CACHE_NAME = 'my-cache-<?php echo $version; ?>'; // ... 其他配置
注意事项
- Service Worker 必须通过 HTTPS 或 localhost 运行
- 注意浏览器兼容性(大部分现代浏览器都支持)
- 合理控制缓存大小,避免占用过多存储空间
- 提供用户手动清除缓存的选项
- 测试离线功能时,使用 Chrome DevTools 的 Network 面板模拟离线
建议根据项目规模和需求选择合适的方案,对于重要的Web应用,推荐使用 Service Worker + Cache API 方案,这是目前最专业、功能最完整的离线缓存实现方式。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播