|
@@ -0,0 +1,334 @@
|
|
|
+;(function() {
|
|
|
+ function initSentry() {
|
|
|
+ try {
|
|
|
+ Sentry.init({
|
|
|
+ dsn: "https://ea0521e5b3584ca1879b940c165916e4@jysentry.jydev.jianyu360.cn/3",
|
|
|
+ release: "v8.8.48.2",
|
|
|
+ environment: "produce",
|
|
|
+ sampleRate: 0.01
|
|
|
+ });
|
|
|
+ Sentry.setTag("url", location.href);
|
|
|
+ var id = document.cookie.match(/(^|;)\s*ud_safe\s*=\s*([^;]+)/);
|
|
|
+ Sentry.setUser({id: id && id[2]})
|
|
|
+ } catch (e) {
|
|
|
+ console.warn(e)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ initSentry();
|
|
|
+ /**
|
|
|
+ * 0. 是否需要安装、卸载SW
|
|
|
+ * 1. 全局异常检测
|
|
|
+ * 2. 判断是否需要激活SW刷新页面
|
|
|
+ */
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 初始化sw脚本
|
|
|
+ * @param callback(params) - 回调函数
|
|
|
+ * params.active - 是否注册SW成功
|
|
|
+ * params.update - 是否激活并与SW通信成功
|
|
|
+ * params.remove - 是否移除SW成功
|
|
|
+ */
|
|
|
+ function initServiceWorkerScript (callback = () => {}) {
|
|
|
+ const hasServiceWorker = typeof navigator.serviceWorker !== 'undefined'
|
|
|
+ if (hasServiceWorker) {
|
|
|
+ const runSw = true
|
|
|
+ try {
|
|
|
+ navigator.serviceWorker.register('/sw.js').then((registration) => {
|
|
|
+ if (runSw) {
|
|
|
+ try {
|
|
|
+ registration.active.postMessage({
|
|
|
+ type: 'update-sw-cache'
|
|
|
+ })
|
|
|
+ callback({
|
|
|
+ active: true,
|
|
|
+ update: true
|
|
|
+ })
|
|
|
+ } catch (err) {
|
|
|
+ console.warn(err)
|
|
|
+ callback({
|
|
|
+ active: true,
|
|
|
+ update: false
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ registration.unregister().then(() => {
|
|
|
+ callback({
|
|
|
+ active: false,
|
|
|
+ remove: true
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }).catch((err) => {
|
|
|
+ console.warn(err)
|
|
|
+ callback({
|
|
|
+ active: false
|
|
|
+ })
|
|
|
+ })
|
|
|
+ } catch (err) {
|
|
|
+ console.warn(err)
|
|
|
+ callback({
|
|
|
+ active: false
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ callback({
|
|
|
+ active: false
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // initServiceWorkerScript()
|
|
|
+
|
|
|
+ let appendCDNDialogState = false
|
|
|
+ // 插入弹窗 Node
|
|
|
+ function addCDNDialogNode (content, confirm = false) {
|
|
|
+ //console.log('[cdn]', 'add', content, confirm)
|
|
|
+ if (!appendCDNDialogState) {
|
|
|
+ const cdnStyle = document.createElement('style')
|
|
|
+ cdnStyle.innerHTML = `
|
|
|
+ .cdn-tip--dialog.show.action-tip .tip-button--submit {
|
|
|
+ display: none;
|
|
|
+ }
|
|
|
+ .cdn-tip--dialog.show,
|
|
|
+ .cdn-tip--dialog.show button{
|
|
|
+ display: inline-block;
|
|
|
+ }
|
|
|
+ .cdn-tip--dialog {
|
|
|
+ position: fixed;
|
|
|
+ top: 20%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translateX(-50%);
|
|
|
+ display: none;
|
|
|
+ box-shadow: 0 0 2px 1px #e0e0e0;
|
|
|
+ border-radius: 8px;
|
|
|
+ background: #FFF;
|
|
|
+ padding: 32px;
|
|
|
+ color: #686868;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 14px;
|
|
|
+ font-style: normal;
|
|
|
+ font-weight: 400;
|
|
|
+ line-height: 22px;
|
|
|
+ }
|
|
|
+ .cdn-tip--dialog button.tip-button--submit {
|
|
|
+ background: #2ABED1;
|
|
|
+ color: #FFF;
|
|
|
+ }
|
|
|
+ .cdn-tip--dialog button {
|
|
|
+ display: none;
|
|
|
+ border-radius: 6px;
|
|
|
+ width: 132px;
|
|
|
+ height: 36px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ line-height: 36px;
|
|
|
+ border: none;
|
|
|
+ margin: 6px;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+`
|
|
|
+ document.head.appendChild(cdnStyle)
|
|
|
+ }
|
|
|
+ appendCDNDialogState = true
|
|
|
+
|
|
|
+ const CDNDialogNode = document.querySelector('#cdn-tip')
|
|
|
+ const hasCDNDialog = Boolean(CDNDialogNode)
|
|
|
+ if (hasCDNDialog) {
|
|
|
+ if (confirm) {
|
|
|
+ CDNDialogNode.classList.remove('action-tip')
|
|
|
+ } else {
|
|
|
+ CDNDialogNode.classList.add('action-tip')
|
|
|
+ }
|
|
|
+ document.querySelector('#cdn-tip p').innerHTML = content
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const cdnStyle = document.createElement('style')
|
|
|
+ cdnStyle.innerHTML = `
|
|
|
+ <style>
|
|
|
+
|
|
|
+ .cdn-tip--dialog.show.action-tip .tip-button--submit {
|
|
|
+ display: none;
|
|
|
+ }
|
|
|
+ .cdn-tip--dialog.show,
|
|
|
+ .cdn-tip--dialog.show button{
|
|
|
+ display: inline-block;
|
|
|
+ }
|
|
|
+ .cdn-tip--dialog {
|
|
|
+ min-width: 160px;
|
|
|
+ position: fixed;
|
|
|
+ z-index: 9999;
|
|
|
+ top: 20%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translateX(-50%);
|
|
|
+ display: none;
|
|
|
+ box-shadow: 0 0 2px 1px #e0e0e0;
|
|
|
+ border-radius: 8px;
|
|
|
+ background: #FFF;
|
|
|
+ padding: 24px;
|
|
|
+ color: #686868;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 14px;
|
|
|
+ font-style: normal;
|
|
|
+ font-weight: 400;
|
|
|
+ line-height: 22px;
|
|
|
+ }
|
|
|
+ .cdn-tip--dialog button.tip-button--submit {
|
|
|
+ background: #2ABED1;
|
|
|
+ color: #FFF;
|
|
|
+ }
|
|
|
+ .cdn-tip--dialog button {
|
|
|
+ display: none;
|
|
|
+ border-radius: 6px;
|
|
|
+ width: 132px;
|
|
|
+ height: 36px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ line-height: 36px;
|
|
|
+ border: none;
|
|
|
+ margin: 6px;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ </style>
|
|
|
+`
|
|
|
+ document.head.appendChild(cdnStyle)
|
|
|
+
|
|
|
+ const cdnNode = document.createElement('div')
|
|
|
+ cdnNode.innerHTML = `
|
|
|
+ <div class="cdn-tip--dialog show ${confirm ? '' : 'action-tip'}" id="cdn-tip">
|
|
|
+ <p>
|
|
|
+ ${content}
|
|
|
+ </p>
|
|
|
+ <div>
|
|
|
+ <button onclick="location.reload()" class="tip-button--submit">刷新重试</button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ `
|
|
|
+ if (document.body) {
|
|
|
+ document.body.appendChild(cdnNode)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 异常资源数组
|
|
|
+ const failedResources = []
|
|
|
+ // 异常域名数组
|
|
|
+ const domains = []
|
|
|
+ // 备用域名映射
|
|
|
+ const BackCDNs = {
|
|
|
+ 'cdn-jybx-webtest.jydev.jianyu360.com': 'jybx-webtest.jydev.jianyu360.com',
|
|
|
+ 'cdn-ali.jianyu360.cn': 'cdn-ali.jianyu360.com',
|
|
|
+ 'cdn-ali2.jianyu360.cn': 'cdn-ali2.jianyu360.com',
|
|
|
+ 'cdn-ali3.jianyu360.cn': 'cdn-ali3.jianyu360.com',
|
|
|
+ 'cdn-ali4.jianyu360.cn': 'cdn-ali4.jianyu360.com',
|
|
|
+ 'cdn-common.jianyu360.cn': 'cdn-common.jianyu360.com'
|
|
|
+ }
|
|
|
+ // 需要检测的域名索引
|
|
|
+ const BackDomains = Object.keys(BackCDNs)
|
|
|
+
|
|
|
+ // 处理异常资源
|
|
|
+ const handleResourceError = (url) => {
|
|
|
+ failedResources.push(url);
|
|
|
+ // 提取域名
|
|
|
+ const domain = new URL(url).hostname
|
|
|
+ if(!domains.includes(domain)) {
|
|
|
+ domains.push(domain)
|
|
|
+ }
|
|
|
+ // 是否存在需要检测的域名
|
|
|
+ if (BackDomains.includes(domain)) {
|
|
|
+ addCDNDialogNode('加载中……')
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 监听错误事件
|
|
|
+ window.addEventListener('error', (e) => {
|
|
|
+ // 脚本错误、图片错误
|
|
|
+ if(e.target.src && (e.target.tagName === 'SCRIPT' || e.target.tagName === 'IMG')) {
|
|
|
+ handleResourceError(e.target.src)
|
|
|
+ }
|
|
|
+
|
|
|
+ // CSS错误
|
|
|
+ if(e.target.href && e.target.tagName === 'LINK') {
|
|
|
+ handleResourceError(e.target.href)
|
|
|
+ }
|
|
|
+ }, true)
|
|
|
+
|
|
|
+ const currentTime = Date.now()
|
|
|
+
|
|
|
+ function sendError (content) {
|
|
|
+ if (window.Sentry && typeof window.Sentry.captureMessage === 'function') {
|
|
|
+ Sentry.captureMessage(content)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ window.addEventListener('load', () => {
|
|
|
+ // 页面完全加载完毕
|
|
|
+ // console.log('load Failed resources:', failedResources)
|
|
|
+ // console.log('load Extracted domains:', domains)
|
|
|
+
|
|
|
+ const hasBackCDN = Object.keys(BackCDNs).some(v => domains.includes(v))
|
|
|
+ // console.log('异常域名是否包含备用', hasBackCDN)
|
|
|
+
|
|
|
+ const canNext = domains.length && hasBackCDN
|
|
|
+ // console.log('是否存在可修复的异常域名', canNext)
|
|
|
+
|
|
|
+ if (canNext) {
|
|
|
+ // 存储
|
|
|
+ caches.open('CDN_INSPECT_2SW').then(cache => {
|
|
|
+ cache.put('/CDN-DATA', new Response(JSON.stringify({
|
|
|
+ FailedCDNs: domains,
|
|
|
+ BackCDNs: BackCDNs
|
|
|
+ })))
|
|
|
+ })
|
|
|
+
|
|
|
+ sendError("[CDN] Has wrong cdn: " + domains.join('、'))
|
|
|
+ addCDNDialogNode('加载中……')
|
|
|
+
|
|
|
+ function stopUnlimitedReload (callback) {
|
|
|
+ const saveKey = 'cdn-reload-page--' + location.href
|
|
|
+ const cachePageInfo = JSON.parse(sessionStorage.getItem(saveKey) || '{}')
|
|
|
+
|
|
|
+ const updateCacheAndReload = (updateTime, count, reloadTime) => {
|
|
|
+ cachePageInfo.update = updateTime
|
|
|
+ cachePageInfo.count = count
|
|
|
+ sessionStorage.setItem(saveKey, JSON.stringify(cachePageInfo))
|
|
|
+ setTimeout(() => {
|
|
|
+ callback(true)
|
|
|
+ }, reloadTime)
|
|
|
+ }
|
|
|
+
|
|
|
+ if (cachePageInfo && cachePageInfo.update) {
|
|
|
+ const lastUpdateState = currentTime - cachePageInfo.update < 4000
|
|
|
+ if (lastUpdateState) {
|
|
|
+ if (cachePageInfo.count < 3) {
|
|
|
+ cachePageInfo.count++
|
|
|
+ updateCacheAndReload(currentTime, cachePageInfo.count, 1000 + (100 * cachePageInfo.count))
|
|
|
+ } else {
|
|
|
+ callback(false)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ updateCacheAndReload(currentTime, 1, 1000)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ updateCacheAndReload(currentTime, 1, 1000)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ initServiceWorkerScript( function (params) {
|
|
|
+ //console.log('[cdn]', params, 'params')
|
|
|
+ if (params.active) {
|
|
|
+ sendError("[CDN] Supported")
|
|
|
+ stopUnlimitedReload(function (state) {
|
|
|
+ //console.log('[cdn]', 'state', state)
|
|
|
+ if (state) {
|
|
|
+ location.reload()
|
|
|
+ } else {
|
|
|
+ sendError("[CDN] Need update Supported")
|
|
|
+ addCDNDialogNode('抱歉,当前故障暂无法自动修复<br>请联系剑鱼标讯客服(400-108-6670)帮您尽快解决', true)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ sendError("[CDN] Not supported")
|
|
|
+ addCDNDialogNode('抱歉,当前故障暂无法自动修复<br>请联系剑鱼标讯客服(400-108-6670)帮您尽快解决')
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+})();
|