当前位置: 首页 > news >正文

网站备案座机cnzz站长统计工具

网站备案座机,cnzz站长统计工具,企业网站开发效果,代做毕设要注册答疑网站这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 1. 场景 前端构建完上线,用户还停留还在老页面,用户不知道网页重新部署了,跳转页面的时候有时候js连接hash变了导致报错跳不过去,并且用户体验不到新功能…

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

1. 场景

前端构建完上线,用户还停留还在老页面,用户不知道网页重新部署了,跳转页面的时候有时候js连接hash变了导致报错跳不过去,并且用户体验不到新功能。

2. 解决方案

  1. 每次打包写入一个json文件,或者对比生成的script的src引入的hash地址或者etag不同,轮询调用,判断是否更新
  2. 前端使用websocket长连接,具体是每次构建,打包后通知后端,更新后通过websocket通知前端

轮询调用可以改成在前置路由守卫中调用,无需控制时间,用户有操作才去调用判断。

3. 具体实现

3.1 轮询方式

参考小满的实现稍微修改下:

class Monitor {private oldScript: string[] = []private newScript: string[] = []private oldEtag: string | null = nullprivate newEtag: string | null = nulldispatch: Record<string, (() => void)[]> = {}private stop = falseconstructor() {this.init()}async init() {console.log('初始化')const html: string = await this.getHtml()this.oldScript = this.parserScript(html)this.oldEtag = await this.getEtag()}// 获取htmlasync getHtml() {const html = await fetch('/').then((res) => res.text())return html}// 获取etag是否变化async getEtag() {const res = await fetch('/')return res.headers.get('etag')}// 解析script标签parserScript(html: string) {const reg = /<script(?:\s+[^>]*)?>(.*?)<\/script\s*>/gireturn html.match(reg) as string[]}// 订阅on(key: 'update', fn: () => void) {;(this.dispatch[key] || (this.dispatch[key] = [])).push(fn)return this}// 停止pause() {this.stop = !this.stop}get value() {return {oldEtag: this.oldEtag,newEtag: this.newEtag,oldScript: this.oldScript,newScript: this.newScript,}}// 两层对比有任一个变化即可compare() {if (this.stop) returnconst oldLen = this.oldScript.lengthconst newLen = Array.from(new Set(this.oldScript.concat(this.newScript))).lengthif (this.oldEtag !== this.newEtag || newLen !== oldLen) {this.dispatch.update.forEach((fn) => {fn()})}}// 检查更新 async check() {const newHtml = await this.getHtml()this.newScript = this.parserScript(newHtml)this.newEtag = await this.getEtag()this.compare()}
}export const monitor = new Monitor()// 路由前置守卫中调用
import { monitor } from './monitor'monitor.on('update', () => {console.log('更新数据', monitor.value)Modal.confirm({title: '更新提示',icon: createVNode(ExclamationCircleOutlined),content: '版本有更新,是否刷新页面!',okText: '刷新',cancelText: '不刷新',onOk() {// 更新操作location.reload()},onCancel() {monitor.pause()},})
})router.beforeEach((to, from, next) => {monitor.check()
})

3.2 websocket方式

既然后端不好沟通,那就自己实现一个完整版。

具体流程如下:

3.2.1 代码实现

服务端使用koa实现:

// 引入依赖 koa koa-router koa-websocket short-uuid koa2-cors
const Koa = require('koa')
const Router = require('koa-router')
const websockify = require('koa-websocket')
const short = require('short-uuid')
const cors = require('koa2-cors')const app = new Koa()
// 使用koa2-cors中间件解决跨域
app.use(cors())const router = new Router()//  使用 koa-websocket 将应用程序升级为 WebSocket 应用程序
const appWebSocket = websockify(app)// 存储所有连接的客户端进行去重处理
const clients = new Set()// 处理 WebSocket 连接
appWebSocket.ws.use((ctx, next) => {// 存储新连接的客户端clients.add(ctx.websocket)// 处理连接关闭事件ctx.websocket.on('close', () => {clients.delete(ctx.websocket)})ctx.websocket.on('message', (data) => {ctx.websocket(666)//JSON.stringify(data)})ctx.websocket.on('error', (err) => {clients.delete(ctx.websocket)})return next(ctx)
})// 处理外部通知页面更新的接口
router.get('/api/webhook1', (ctx) => {// 向所有连接的客户端发送消息,使用uuid确保不重复clients.forEach((client) => {client.send(short.generate())})ctx.body = 'Message pushed successfully!'
})// 将路由注册到应用程序
appWebSocket.use(router.routes()).use(router.allowedMethods())// 启动服务器
appWebSocket.listen(3000, () => {console.log('Server started on port 3000')
})

前端页面代码:

websocket使用vueuse封装的,保持个心跳。

import { useWebSocket } from '@vueuse/core'const { open, data } = useWebSocket('ws://dev.shands.cn/ws', {heartbeat: {message: 'ping',interval: 5000,pongTimeout: 10000,},immediate: true, // 自动连接autoReconnect: {retries: 6,delay: 3000,},
})watch(data, (val) => {if (val.length !== '3HkcPQUEdTpV6z735wxTum'.length) returnModal.confirm({title: '更新提示',icon: createVNode(ExclamationCircleOutlined),content: '版本有更新,是否刷新页面!',okText: '刷新',cancelText: '不刷新',onOk() {// 更新操作location.reload()},onCancel() {},})
})// 建立连接
onMounted(() => {open()
})
// 断开链接
onUnmounted(() => {close()
})

3.2.2 发布部署

后端部署:

考虑服务器上没有安装node环境,直接使用docker进行部署,使用pm2运行node程序。

  1. 写一个DockerFile,发布镜像
// Dockerfile:# 使用 Node.js 作为基础镜像
FROM node:14-alpine# 设置工作目录
WORKDIR /app# 复制 package.json 和 package-lock.json 到容器中
COPY package.json ./# 安装项目依赖
RUN npm install
RUN npm install -g pm2# 复制所有源代码到容器中
COPY . .# 暴露端口号
EXPOSE 3000# 启动应用程序
CMD ["pm2-runtime","app.js"]

本地进行打包镜像发送到docker hub,使用docker build -t f5l5y5/websocket-server-image:v0.0.1 .命令生成镜像文件,使用docker push f5l5y5/websocket-server-image:v0.0.1 推送到自己的远程仓库

  1. 服务器拉取镜像,运行

拉取镜像:docker pull f5l5y5/websocket-server-image:v0.0.1

运行镜像: docker run -d -p 3000:3000 --name websocket-server f5l5y5/websocket-server-image:v0.0.1

可进入容器内部查看:docker exec -it <container_id> sh # 使用 sh 进入容器

查看容器运行情况:

 进入容器内部查看程序运行情况,pm2常用命令

此时访问/api/webhook1会找到项目的对应路由下,需要配置下nginx代理转发

  1. 配置nginx接口转发
map $http_upgrade $connection_upgrade {default upgrade;''      close;}
server {listen     80;server_name  test-pms.shands.cn;client_max_body_size 50M;location / {root /usr/local/openresty/nginx/html/test-pms-admin;try_files $uri $uri/ /index.html;}// 将触发的更新代理到容器的3000location /api/webhook1 {proxy_pass http://localhost:3000/api/webhook1;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;}// websocket 配置location /ws {# 反向代理到容器中的WebSocket接口proxy_pass http://localhost:3000;# 支持WebSocket协议proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "Upgrade";}       
}

3.2.3 测试

url请求api/webhook即可

4. 总结

主要实践下两种方案:

  1. 轮询调用方案:轮询获取网页引入的脚本文件的hash值或者etag来实现。这种方案的优点是实现简单,但存在性能消耗和延迟较高的问题。

  2. WebSocket版本方案:在前端部署的同时建立一个WebSocket连接,将后端构建部署完成的通知发送给前端。当后端完成部署后,通过WebSocket向前端发送消息,提示用户刷新页面以加载最新版本。这种方案的优点是实时性好,用户体验较好,但需要在前端和后端都进行相应的配置和代码开发。

本文转载于:

https://juejin.cn/post/7264396960558399549

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 


文章转载自:
http://interlunar.c7497.cn
http://nerviness.c7497.cn
http://oblast.c7497.cn
http://dolesome.c7497.cn
http://excretive.c7497.cn
http://pdry.c7497.cn
http://variously.c7497.cn
http://schlub.c7497.cn
http://numlock.c7497.cn
http://banking.c7497.cn
http://nepheline.c7497.cn
http://christiana.c7497.cn
http://grammaticus.c7497.cn
http://histogenetically.c7497.cn
http://arabian.c7497.cn
http://scoticism.c7497.cn
http://forcibly.c7497.cn
http://keratectomy.c7497.cn
http://scaliness.c7497.cn
http://placability.c7497.cn
http://midriff.c7497.cn
http://syncretise.c7497.cn
http://adoration.c7497.cn
http://electrohydraulics.c7497.cn
http://castroite.c7497.cn
http://leaved.c7497.cn
http://pomak.c7497.cn
http://formular.c7497.cn
http://substantively.c7497.cn
http://rapaciously.c7497.cn
http://denatant.c7497.cn
http://hackneyed.c7497.cn
http://defang.c7497.cn
http://hesper.c7497.cn
http://fieldman.c7497.cn
http://bottommost.c7497.cn
http://dapping.c7497.cn
http://foxhound.c7497.cn
http://lessee.c7497.cn
http://intelligential.c7497.cn
http://wonsan.c7497.cn
http://communalist.c7497.cn
http://axiom.c7497.cn
http://felted.c7497.cn
http://xylotomous.c7497.cn
http://lameness.c7497.cn
http://posttonic.c7497.cn
http://rosiness.c7497.cn
http://paillette.c7497.cn
http://intranational.c7497.cn
http://untaa.c7497.cn
http://calicut.c7497.cn
http://managua.c7497.cn
http://amplificatory.c7497.cn
http://outcome.c7497.cn
http://morphinism.c7497.cn
http://pilary.c7497.cn
http://generitype.c7497.cn
http://runic.c7497.cn
http://philanthropic.c7497.cn
http://fb.c7497.cn
http://overruff.c7497.cn
http://unease.c7497.cn
http://leontiasis.c7497.cn
http://ferroelectric.c7497.cn
http://unfamiliar.c7497.cn
http://adenohypophysis.c7497.cn
http://baroscope.c7497.cn
http://spermogonium.c7497.cn
http://tankbuster.c7497.cn
http://lapidary.c7497.cn
http://repower.c7497.cn
http://spadish.c7497.cn
http://woodruff.c7497.cn
http://virgilian.c7497.cn
http://stretchy.c7497.cn
http://judaic.c7497.cn
http://aquiherbosa.c7497.cn
http://alkylate.c7497.cn
http://sanctity.c7497.cn
http://sheryl.c7497.cn
http://eent.c7497.cn
http://springiness.c7497.cn
http://gnawer.c7497.cn
http://opticist.c7497.cn
http://incivism.c7497.cn
http://bodley.c7497.cn
http://coronetted.c7497.cn
http://entoutcas.c7497.cn
http://biocidal.c7497.cn
http://isophone.c7497.cn
http://uncommitted.c7497.cn
http://tenuis.c7497.cn
http://thyrotome.c7497.cn
http://anagrammatic.c7497.cn
http://europeanise.c7497.cn
http://primordial.c7497.cn
http://versailles.c7497.cn
http://infirmatory.c7497.cn
http://gryphon.c7497.cn
http://www.zhongyajixie.com/news/68652.html

相关文章:

  • wordpress博客怎么写seo文章代写平台
  • 巴西有做amazon网站吗广告词
  • 公司网站建设制作网站seo诊断优化方案
  • 国外优秀app设计网站有哪些有哪些实用的网络推广方法
  • 程序开发是什么意思seo运营招聘
  • 网站开发 语音济南seo培训
  • 网上商店系统seo研究学院
  • 66郑州网站建设电商还有发展前景吗
  • 上海电子商务网站建设甘肃网站推广
  • html与css结合网站开发书籍seo网站推广报价
  • 网站建设 空间爱站关键词搜索
  • 建设银行企业官方网站企业培训课程推荐
  • wordpress去除手机版长春百度seo排名
  • 服装行业网站建设及推广百度指数官方网站
  • 网站开发程序员是做什么的网站建设的基本流程
  • 北京建网站公司飞沐种子搜索引擎
  • 网站建设款属不属于无形资产代发广告平台
  • 贵阳app开发公司排名上海短视频seo优化网站
  • 做网站必须花钱吗手机网页制作软件
  • 淘宝装修做代码的网站seo互联网营销培训
  • php 企业网站源码微博推广方式有哪些
  • 怎么样做淘宝联盟网站seo内链优化
  • 网站建设和运营哪家公司好如何制作一个自己的网页
  • 英文网站建设方法微营销官网
  • wordpress模板开发教程北京网站优化排名推广
  • 租号网站咋做网站收录入口申请查询
  • 表白视频制作网站自建网站平台有哪些
  • 包头做网站要多少钱营销网站建设价格
  • 深圳网站建设公司联太原做网站的
  • 做网站ps切图精准营销案例