【前端】PWA

目录

  • 概述
    • 实战
    • vue项目
    • 问题汇总

PWA(渐进式 Web 应用,Progressive Web App) 2015提出

概述

PWA 是一种提升 Web 应用体验的技术,使其具备与原生应用相似的功能和性能。PWA不仅能够在网页上运行,还能在手机或桌面上像传统的移动应用一样进行交互,同时保留了Web应用的灵活性。
它通过借助一些先进的功能,如Service Workers、Web App Manifest 和 Push Notifications 等,来提升用户体验、优化性能,并能在离线或低网速环境下依然保持可用性。
PWA 强调的是“渐进式”,即可以根据设备的能力逐步增强其功能。

  • 主要特点:
    • 离线支持: 使用 Service Worker,可以使应用在没有网络连接时也能运行。Service Worker 是一种浏览器后台脚本,能够拦截并缓存网络请求,使得 Web 应用在离线状态下仍然能够继续工作。
    • 推送通知: PWA 可以向用户推送通知,即使他们没有打开应用/应用没有运行,提升用户参与度。
    • 响应式设计: PWA 具有响应式设计,可以适应不同的屏幕尺寸和设备,提供一致的用户体验。
    • 安装到主屏幕:通常通过 Web App Manifest 文件配置,它提供了有关应用外观、名称、图标等信息。
      PWA 可以通过浏览器直接安装到设备的主屏幕,用户像安装本地应用一样,直接启动 PWA,而无需经过应用商店。安装后,PWA 会像原生应用一样运行,且不显示浏览器界面。
    • 快速加载: 通过资源缓存、懒加载和其他性能优化手段,PWA 可以提供比传统 Web 应用更快速的加载体验。
    • 自更新:PWA 可以在后台自动更新内容和资源,使得用户始终体验到最新版本的应用。
    • 提高性能
      由于 Service Worker 能够缓存重要资源,PWA 可以大幅度提高应用的加载速度,减少网络请求。
  • 使用场景:
    需要在没有稳定网络的情况下工作,如离线文档编辑器、离线新闻阅读器等。
    需要提升用户参与度的应用,通过推送通知与用户保持互动。
    需要跨平台应用并提供与原生应用相似体验的 Web 应用。

实战

  • PWA 的技术组成
  1. Web App Manifest
    这是一个JSON文件,告诉浏览器如何显示应用,包括应用的名称、图标、启动页面、主题颜色等。它允许用户将 PWA 添加到主屏幕并像原生应用一样使用。
{"name": "My PWA App","short_name": "PWA","start_url": "/","display": "standalone","background_color": "#ffffff","theme_color": "#0000ff","icons": [{"src": "icons/icon-192x192.png","sizes": "192x192","type": "image/png"},{"src": "icons/icon-512x512.png","sizes": "512x512","type": "image/png"}]
}
  1. Service Worker
    Service Worker 是一个在浏览器后台运行的脚本,它可以拦截网络请求,缓存资源并提供离线支持。Service Worker 还可以实现推送通知和后台数据同步等功能。

编写 Service Worker 注册脚本
在你的主文件(例如 index.js 或 app.js)中调用 registerServiceWorker
确保你的 manifest.json 文件配置正确

// registerServiceWorker.jsexport function register() {if ('serviceWorker' in navigator) {window.addEventListener('load', () => {const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;  // 指定 Service Worker 的路径navigator.serviceWorker.register(swUrl).then(registration => {console.log('Service Worker registered with scope: ', registration.scope);}).catch(error => {console.log('Service Worker registration failed: ', error);});});}
}export function unregister() {if ('serviceWorker' in navigator) {navigator.serviceWorker.ready.then(registration => {registration.unregister().then(success => {if (success) {console.log('Service Worker unregistered');}}).catch(error => {console.log('Service Worker unregistration failed: ', error);});});}
}// index.js 或 app.jsimport React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { register } from './registerServiceWorker';  // 导入 register 函数// 注册 Service Worker
register();ReactDOM.render(<React.StrictMode><App /></React.StrictMode>,document.getElementById('root')
);

创建 Service Worker 脚本
在 service-worker.js 中,你可以缓存应用资源,处理离线请求等。

// service-worker.jsconst CACHE_NAME = 'my-cache-v1';
const urlsToCache = ['/','/index.html','/styles.css','/script.js', // 你所有的静态文件,或者可以使用通配符
];// 安装阶段,缓存静态资源
self.addEventListener('install', event => {event.waitUntil(caches.open(CACHE_NAME).then(cache => {console.log('Opened cache');return cache.addAll(urlsToCache);}));
});// 激活阶段,清理过时的缓存
self.addEventListener('activate', event => {const cacheWhitelist = [CACHE_NAME];event.waitUntil(caches.keys().then(cacheNames => {return Promise.all(cacheNames.map(cacheName => {if (!cacheWhitelist.includes(cacheName)) {return caches.delete(cacheName);}}));}));
});// 拦截网络请求,使用缓存响应请求
self.addEventListener('fetch', event => {event.respondWith(caches.match(event.request).then(cachedResponse => {if (cachedResponse) {return cachedResponse;  // 如果缓存中有匹配的资源,直接返回}return fetch(event.request);  // 否则正常请求}));
});
  1. HTTPS
    PWA 强烈推荐使用 HTTPS,因为 Service Worker 只能在安全的环境下运行,且 HTTPS 提供了更高的安全性。

vue项目

在 Vue + Vite 项目中实现 离线缓存(离线也能访问) 的最佳方案是使用 PWA(Progressive Web App)技术。你可以使用官方推荐的插件:vite-plugin-pwa,支持离线缓存、自动注册 Service Worker、更新机制等。
yarn add vite-plugin-pwa -D
修改vite.config.js

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { VitePWA } from 'vite-plugin-pwa';export default defineConfig({plugins: [vue(),VitePWA({registerType: 'autoUpdate', // 自动更新 Service WorkerincludeAssets: ['favicon.svg', 'robots.txt'], // 可选:缓存额外资源manifest: {name: 'My Vue App',short_name: 'VueApp',description: '我的离线 Vue 应用',theme_color: '#ffffff',icons: [{src: 'pwa-192x192.png',sizes: '192x192',type: 'image/png',},{src: 'pwa-512x512.png',sizes: '512x512',type: 'image/png',},],},}),],
});//缓存public下所有文件 
import { defineConfig } from 'vite'
import { VitePWA } from 'vite-plugin-pwa'export default defineConfig({plugins: [VitePWA({registerType: 'autoUpdate',includeAssets: ['favicon.ico', 'robots.txt', '**/*'], // ✅ 显式包含 public 下所有文件workbox: {globPatterns: ['**/*.{js,css,html,ico,png,svg,json,txt,woff2}'], // ✅ 缓存这些后缀的文件runtimeCaching: [{urlPattern: /^\/.*\.(json|png|ico|svg|html|js|css|txt)$/,handler: 'CacheFirst',options: {cacheName: 'static-assets',expiration: {maxEntries: 1000,maxAgeSeconds: 60 * 60 * 24 * 30, // 缓存 30 天},},},],},}),],
})
配置项用途执行时机作用范围
includeAssets👇构建时复制到 dist/,并加入到 PWA 资源清单构建时主要针对 public/ 目录的资源
globPatterns👇构建时让 Workbox 自动缓存匹配的静态资源构建时所有 dist/ 中能匹配的文件
urlPattern👇运行时拦截某些请求并决定是否缓存、如何缓存运行时(浏览器端)任意运行时资源(API、图片等)
类型示例资源推荐用法
静态资源/robots.txt、faviconincludeAssets + globPatterns
公共 JSON/data/config.jsonincludeAssets or runtimeCaching
接口数据/api/user/listruntimeCaching.urlPattern
图片资源/images/logo.pngglobPatterns + runtimeCaching

添加图标文件(放在 public/ 目录)
在入口文件注册 Service Worker: 如果使用 vite-plugin-pwa 的 autoUpdate,你不需要手动注册,插件会自动帮你做。

if ('serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('/sw.js');});
}

构建项目并部署,提示 “安装应用”,并具备 离线访问能力。

  • 测试
    打开浏览器访问你的项目
    F12 打开开发者工具 → 应用(Application) → Service Workers
    断网,再刷新页面,页面依然能打开,说明离线缓存成功
    service worker只能在 HTTPS环境/localhost本地测试环境 中使用,否则浏览器会阻止
    在这里插入图片描述
    service worker的东西在cache storage里面
    在这里插入图片描述
    safari只能看是否开启,看不了存的内容
    在这里插入图片描述

  • 控制哪些资源缓存
    使用 workbox 的 runtimeCaching 来配置路由缓存策略

VitePWA({workbox: {runtimeCaching: [{urlPattern: /^https:\/\/your-api\.com\/.*$/,handler: 'NetworkFirst',options: {cacheName: 'api-cache',},},],},
});
  • 注意开发环境不会启用离线缓存,因为防止有缓存后调试困难
    要测试离线功能,必须使用 build 后的生产版本。
npm install -g serve
serve dist#oryarn build         # 构建生产代码
npx serve dist     # 启动本地静态服务器(正式环境)

问题汇总

  1. Uncaught (in promise) SecurityError: Failed to register a ServiceWorker for scope (‘https://192.168.1.x:417x/’) with script (‘https://192.168.1.x:417x/sw.js’): An SSL certificate error occurred when fetching the script.
    表示正在尝试在使用 自签名证书或无效 HTTPS 证书 的本地开发服务器上注册 Service Worker,而 浏览器出于安全原因阻止了这个请求。
  • 解决方法 选其一
    (1) localhost地址是ok的 或者
    (2)使用受信任的证书:
    如果你 必须通过 IP 地址 + HTTPS 访问,你需要:
    为你的 IP 或本地域名(如 my-app.local)生成一个自签名证书;
    将该证书导入到本地的「受信任根证书」;
    配置 Vite 使用该证书。
    这过程较复杂,通常不推荐在本地开发中这么做,除非你对证书比较熟悉。
    1)安装
brew install mkcert
brew install nss # 如果你使用 Firefox

Windows:直接在 https://github.com/FiloSottile/mkcert 下载对应版本,解压到 PATH 中。
2)创建本地 CA(仅第一次需要)mkcert -install这会自动生成并安装本地根证书到受信任列表中(支持 macOS、Windows、Linux)。
3)为 IP 地址创建证书(例如 192.168.1.4)
mkcert 192.168.1.4
会生成两个文件:
192.168.1.4.pem(证书)
192.168.1.4-key.pem(私钥)
4) 配置 Vite 使用这个证书
将文件重命名为更简洁的名字:

mv 192.168.1.4.pem server.crt
mv 192.168.1.4-key.pem server.key

在 vite.config.ts 中配置:

import { defineConfig } from 'vite';
import fs from 'fs';export default defineConfig({server: {https: {key: fs.readFileSync('./server.key'),cert: fs.readFileSync('./server.crt'),},host: '192.168.1.4',port: 4173}
});

现在可以访问:https://192.168.1.x:417x。不会有证书警告,且 Service Worker 能正常注册。
2. 桌面chrome的Service Worker 正常工作,安卓chrome还是没存上
手机端检查service worker,chrome://serviceworker-internals 已被废弃,故使用:在手机上打开 DevTools(推荐)
电脑和手机连接同一个 Wi-Fi
手机开启开发者模式 + USB 调试
用数据线连接电脑
电脑 Chrome 打开:
chrome://inspect/#devices
在手机 Chrome 中打开你要调试的网页
电脑端点击 inspect,就能打开该网页的 DevTools(像桌面一样调试)
切换到 DevTools 的 “Application” → “Service Workers” 面板查看注册情况

  1. An SSL certificate error occurred when fetching the script.了解此错误
    index.html:1 Uncaught (in promise) SecurityError: Failed to register a ServiceWorker for scope (‘https://xx/’) with script (‘https://xx/sw.js’): An SSL certificate error occurred when fetching the script.
    试图在 HTTPS 本地开发环境 注册 Service Worker,但浏览器因为 SSL 证书不受信任 而阻止了注册。
    必须把证书 xx.pem 安装到手机上,安装后还要启用“信任用户证书”(安卓设置中),否则浏览器依然会报“SSL 证书错误”,Service Worker 无法注册。
    1)准备证书(把 .pem 转为 .crt)安卓只识别 .crt 格式证书。在电脑上把 .pem 转为 .crt:打开终端,运行:cp 192.168.1.4.pem 192.168.1.4.crt简单改扩展名,因为 mkcert 生成的 .pem 实际上就是 X.509 格式。
  1. 把证书传到手机
    3)安装证书 不同厂商界面略有不同
  • 安卓10
    打开设置 → 安全 或 安全与隐私
    选择:加密与凭据 或 更多安全设置
    点击:从存储设备安装 或 安装证书
    选择你刚才传进去的证书
    选择安装为:【VPN 和应用程序(用户)】
    手机提示“已安装证书”,说明成功。
  1. 开启信任用户证书(某些安卓必须)
    部分安卓系统(尤其是 Android 11 及以上)默认不信任用户安装的证书,你需要手动开启:
    打开浏览器输入 chrome://flags,搜索 “insecure origins treated as secure”
    或手动启用:设置 → 关于手机 → 连续点击版本号 7 次,开启开发者模式/【开发者选项】
    找到:信任用户 CA 证书或类似选项:允许应用信任用户 CA
    ⚠️ 注意:不是所有 ROM 都提供这个选项,如果你的浏览器(尤其是 Chrome)仍然不信任用户证书,就只能部署到支持 HTTPS 的远程服务器(如 Vercel)。
    5) 验证是否成功
    打开手机浏览器,访问,看地址栏是否出现绿色 🔒 或无警告
    打开 DevTools 调试(用 chrome://inspect)查看 Service Worker 是否正常注册
  1. 在安卓中提示“需要提供私钥才能安装证书”。
    用adb安装到系统证书 或用openssl转换一下再安装
    你导入的是 客户端证书(Client Certificate),而系统安装时需要:
    公钥 + 私钥,并且要打包成 .p12(或 .pfx)格式。
    解决办法:生成 .p12 文件(含私钥)
    你需要用 openssl 将你的公钥和私钥打包成一个 .p12 文件,再传到文石设备上安装。
    所需材料:一个 .crt(或 .pem)文件:公钥证书,一个 .key 文件:私钥文件(必须你自己持有)
#打包命令
openssl pkcs12 -export \-in client.crt \-inkey client.key \-out client.p12 \-name "my-cert"

系统会要求你设置一个导入密码(可以设置一个简单密码)设备安装时要求输入
5. 上述做完,安卓chrome还是不信任该网站

  • 使用vite-plugin-mkcert
    这是一个 Vite 插件,用于:
    为你的本地开发服务器(vite dev)启用 HTTPS
    自动创建并安装受信任的本地开发证书(通过 mkcert)
    这对在 移动设备(如文石)上访问你的本地开发页面 非常重要,因为:
    移动端通常拒绝连接未信任的 HTTP 或自签名 HTTPS,如果你配置了 mkcert,浏览器就可以直接信任你的本地 HTTPS 网站
  • 还是不行,试一下:把证书放进系统 CA 目录
    mkcert 安装时会自动创建一个「根证书(CA)」用于签发你本地开发用的 HTTPS 证书。这个根证书是你要导入安卓系统 CA 的那个证书,mkcert -CAROOT找到位置
    没root的将rootCA.pem发送到手机,直接安装成CA证书,成功让chrome信任了,解决问题✅
    openssl x509 -inform PEM -subject_hash_old -in rootCA.pem | head -1生成一串字符串,记住它,后面加上.0作为新文件的名称
    cp rootCA.pem 新文件名称形如cp rootCA.pem 119xxxxa.0
    通过adb命令放入已root的设备

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/82800.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

湖北理元理律师事务所:从法律合规到心灵契合的服务升维

债务优化不仅是数字游戏&#xff0c;更是信任重建的过程。湖北理元理律师事务所在实践中发现&#xff1a;68%的债务纠纷中存在沟通断裂。为此&#xff0c;机构构建了“三维信任修复机制”。 维度一&#xff1a;信息透明的技术实现 区块链存证舱&#xff1a;客户手机实时查看律…

香橙派3B学习笔记2:Vscode远程SSH登录香橙派_权限问题连接失败解决

Vscode下载插件&#xff0c;ssh远程登录香橙派。 ssh &#xff1a; orangepi本地ip 密码 &#xff1a; orangepi 安装 Remote - SSH 扩展SSH插件&#xff1a; SSH远程连接&#xff1a; ssh usernameremote_host ssh -p port_number usernameremote_host默认22端口号就用第一行…

VMware安装Ubuntu实战分享大纲

深入解析快速排序 一、分治策略分解 分解阶段&#xff1a; 选择基准元素 $pivot$将数组划分为三个子集&#xff1a; $$ left {x | x < pivot} $$ $$ equal {x | x pivot} $$ $$ right {x | x > pivot} $$ 递归排序&#xff1a; 对 left 和 right 子集递归调用快速排…

AI 让无人机跟踪更精准——从视觉感知到智能预测

AI 让无人机跟踪更精准——从视觉感知到智能预测 无人机跟踪技术正在经历一场前所未有的变革。曾经,我们只能依靠 GPS 或简单的视觉识别来跟踪无人机,但如今,人工智能(AI)结合深度学习和高级视觉算法,正让无人机的跟踪变得更加智能化、精准化。 尤其是在自动驾驶、安防监…

GATED DELTA NETWORKS : IMPROVING MAMBA 2 WITH DELTA RULE

TL;DR 2024 年 Nvidia MIT 提出的线性Transformer 方法 Gated DeltaNet&#xff0c;融合了自适应内存控制的门控机制&#xff08;gating&#xff09;和用于精确内存修改的delta更新规则&#xff08;delta update rule&#xff09;&#xff0c;在多个基准测试中始终超越了现有…

Laravel单元测试使用示例

Date: 2025-05-28 17:35:46 author: lijianzhan 在 Laravel 框架中&#xff0c;单元测试是一种常用的测试方法&#xff0c;它是允许你测试应用程序中的最小可测试单元&#xff0c;通常是方法或函数。Laravel 提供了内置的测试工具PHPUnit&#xff0c;实践中进行单元测试是保障代…

【FastAPI】--3.进阶教程(二)

【FastAPI】--进阶教程1-CSDN博客 【FastAPI】--基础教程-CSDN博客 目录 1.FastAPI - CORS ​2.FastAPI - CRUD 操作 2.1.Create 2.2.Read 2.3.Update 2.4.Delete 3.FastAPI - 使用 GraphQL 4.FastAPI - Websockets 5.FastAPI - 事件处理程序 6.FastAPI - 安装 Fla…

FEMFAT许可的更新与升级流程

随着工程仿真技术的不断发展&#xff0c;FEMFAT作为一款领先的疲劳分析软件&#xff0c;持续为用户提供卓越的性能和创新的功能。为了保持软件的最新性和高效性&#xff0c;了解FEMFAT许可的更新与升级流程至关重要。本文将为您详细介绍FEMFAT许可的更新与升级流程&#xff0c;…

麒麟v10,arm64架构,编译安装Qt5.12.8

Window和麒麟x86_64架构&#xff0c;官网提供安装包&#xff0c;麒麟arm64架构的&#xff0c;只能自己用编码编译安装。 注意&#xff0c;“桌面”路径是中文&#xff0c;所以不要把源码放在桌面上编译。 1. 下载源码 从官网下载源码&#xff1a;https://download.qt.io/arc…

20250528-C#知识:结构体

C#知识&#xff1a;结构体 结构体是一种自定义数据类型&#xff0c;用户可以根据自身需求设计自己的结构体用来表示某种数据集合。结构体是一种值类型&#xff0c;结合了值类型的优点&#xff0c;避免了引用类型的缺点。本文简单介绍并探究一下C#中的结构体。 结构体一般写在命…

CRM系统的功能模块划分

基础管理模块 用户管理 用户注册与登录角色权限管理部门组织架构用户信息管理 系统设置 基础参数配置系统日志管理数据字典管理系统监控 客户管理模块 客户信息管理 客户基本信息客户分类管理客户标签管理客户关系图谱 联系人管理 联系人信息联系记录沟通历史重要日期提醒 …

Python中的跨域资源共享(CORS)处理

在Web开发中&#xff0c;跨域资源共享&#xff08;CORS&#xff09;是浏览器强制执行的安全机制&#xff0c;用于控制不同源&#xff08;协议域名端口&#xff09;之间的资源交互。下面我将通过Python示例详细讲解CORS的实现。 原生Python实现CORS Flask框架手动实现CORS fr…

Kruskal算法剖析与py/cpp/Java语言实现

Kruskal算法剖析与py/cpp/Java语言实现 一、Kruskal算法的基本概念1.1 最小生成树1.2 Kruskal算法核心思想 二、Kruskal算法的执行流程三、Kruskal算法的代码实现3.1 Python实现3.2 C实现3.3 Java实现 四、算法复杂度分析4.1 时间复杂度4.2 空间复杂度 五、Kruskal算法应用场景…

微信小程序返回上一页监听

本文实现的是微信小程序在返回上一页时获取通知并自定义业务。 最简单的实现&#xff1a; 使用 wx.enableAlertBeforeUnload() 优点&#xff1a;快速接入 缺点&#xff1a;手势不能识别、无法自定义弹窗内容&#xff08;仅询问&#xff09; 方法二&#xff1a; page-conta…

Excel 统计某个字符串在指定区域出现的次数

【本文概要】 Excel 统计某个字符串在指定区域出现的次数&#xff1a; 1、Excel 统计一个单元格内的某字符串的出现次数 2、Excel 统计某一列所有单元格内的某字符串的出现次数 3、Excel 统计某一区域所有单元格内的某字符串的出现次数 1、Excel 统计一个单元格内的某字符串的出…

生物化学:药品药物 营养和补充剂信息 第三方认证信息 常见误区 汇总

常见维生素和矿物质成分表 成分名称好处副作用&#xff08;超量或敏感情况&#xff09;运作方式推荐日剂量&#xff08;成人&#xff09;剂量说明维生素A&#xff08;视黄醇&#xff09;视力、免疫、皮肤健康过量可致肝损伤、头痛、脱发调节视网膜功能、细胞分化700–900 g RA…

mock库知识笔记(持续更新)

文章目录 mock简介导入方式参数简介使用场景&#xff08;待更新&#xff09;常见问题总结&#xff08;待更新&#xff09;Python代码官网 mock简介 mock是一个模拟对象库&#xff0c;具有模拟其他python对象的功能&#xff0c;还能指定模拟对象的返回值和设置模拟对象的属性。…

扇形 圆形 面积公式

✅ 一、圆的面积公式 全圆面积&#xff1a; A circle π r 2 A_{\text{circle}} \pi r^2 Acircle​πr2 ✅ 二、扇形的面积公式&#xff08;两种制式&#xff09; 弧度制&#xff1a; A sector 1 2 r 2 θ A_{\text{sector}} \frac{1}{2} r^2 \theta Asector​21​r2θ …

怎样将win11+ubuntu双系统的ubuntu从机械硬盘迁移至固态硬盘(1)

将 Ubuntu 从机械硬盘迁移到固态硬盘是一个涉及多个步骤的过程。以下是一个基本的迁移指南&#xff1a; 1. 前期准备 1.1 备份数据&#xff1a; 确保你已备份数据&#xff0c;以防止在迁移过程中出现意外导致任何数据丢失。 1.2 固态硬盘安装&#xff1a; 确保固态硬盘正确…

js中common.js和ECMAScript.js区别

以下是关于 CommonJS 和 ECMAScript Modules&#xff08;ESM&#xff09;的详细对比分析&#xff0c;包含底层原理和示例说明&#xff1a; &#x1f9e9; 核心差异对比表 特性CommonJSES Modules来源Node.js 社区规范ECMAScript 语言标准加载方式动态加载&#xff08;运行时解…