Commit f78657473e85487c09cd3c10112db48a0c4a7c4e
1 parent
8d7d751d
fix(报警推送): 修复报警推送功能无效的问题
该问题原因为 com.genersoft.iot.vmp.conf.GlobalResponseAdvice 类改变了 sse 响应体的数据结构,导致前端无法正确解析 sse 数据,调试后未发现 GlobalResponseAdvice 如何修改的 sse 数据结构,故根据 sse 消息体结构自定义实现了 sse 连接
Showing
6 changed files
with
120 additions
and
87 deletions
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
| 1 | package com.genersoft.iot.vmp.conf.security; | 1 | package com.genersoft.iot.vmp.conf.security; |
| 2 | 2 | ||
| 3 | import com.genersoft.iot.vmp.conf.UserSetting; | 3 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 4 | -import org.springframework.core.annotation.Order; | ||
| 5 | import org.slf4j.Logger; | 4 | import org.slf4j.Logger; |
| 6 | import org.slf4j.LoggerFactory; | 5 | import org.slf4j.LoggerFactory; |
| 7 | import org.springframework.beans.factory.annotation.Autowired; | 6 | import org.springframework.beans.factory.annotation.Autowired; |
| 8 | import org.springframework.context.annotation.Bean; | 7 | import org.springframework.context.annotation.Bean; |
| 9 | import org.springframework.context.annotation.Configuration; | 8 | import org.springframework.context.annotation.Configuration; |
| 9 | +import org.springframework.core.annotation.Order; | ||
| 10 | import org.springframework.security.authentication.AuthenticationManager; | 10 | import org.springframework.security.authentication.AuthenticationManager; |
| 11 | import org.springframework.security.authentication.dao.DaoAuthenticationProvider; | 11 | import org.springframework.security.authentication.dao.DaoAuthenticationProvider; |
| 12 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; | 12 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; |
| @@ -28,6 +28,7 @@ import java.util.Arrays; | @@ -28,6 +28,7 @@ import java.util.Arrays; | ||
| 28 | 28 | ||
| 29 | /** | 29 | /** |
| 30 | * 配置Spring Security | 30 | * 配置Spring Security |
| 31 | + * | ||
| 31 | * @author lin | 32 | * @author lin |
| 32 | */ | 33 | */ |
| 33 | @Configuration | 34 | @Configuration |
| @@ -75,6 +76,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { | @@ -75,6 +76,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { | ||
| 75 | matchers.add("/js/**"); | 76 | matchers.add("/js/**"); |
| 76 | matchers.add("/api/device/query/snap/**"); | 77 | matchers.add("/api/device/query/snap/**"); |
| 77 | matchers.add("/record_proxy/*/**"); | 78 | matchers.add("/record_proxy/*/**"); |
| 79 | + matchers.add("/api/emit"); | ||
| 78 | matchers.addAll(userSetting.getInterfaceAuthenticationExcludes()); | 80 | matchers.addAll(userSetting.getInterfaceAuthenticationExcludes()); |
| 79 | // 可以直接访问的静态数据 | 81 | // 可以直接访问的静态数据 |
| 80 | web.ignoring().antMatchers(matchers.toArray(new String[0])); | 82 | web.ignoring().antMatchers(matchers.toArray(new String[0])); |
| @@ -83,6 +85,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { | @@ -83,6 +85,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { | ||
| 83 | 85 | ||
| 84 | /** | 86 | /** |
| 85 | * 配置认证方式 | 87 | * 配置认证方式 |
| 88 | + * | ||
| 86 | * @param auth | 89 | * @param auth |
| 87 | * @throws Exception | 90 | * @throws Exception |
| 88 | */ | 91 | */ |
| @@ -111,7 +114,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { | @@ -111,7 +114,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { | ||
| 111 | .authorizeRequests() | 114 | .authorizeRequests() |
| 112 | .requestMatchers(CorsUtils::isPreFlightRequest).permitAll() | 115 | .requestMatchers(CorsUtils::isPreFlightRequest).permitAll() |
| 113 | .antMatchers(userSetting.getInterfaceAuthenticationExcludes().toArray(new String[0])).permitAll() | 116 | .antMatchers(userSetting.getInterfaceAuthenticationExcludes().toArray(new String[0])).permitAll() |
| 114 | - .antMatchers("/api/user/login","/index/hook/**","/zlm_Proxy/FhTuMYqB2HeCuNOb/record/t/1/2023-03-25/16:35:07-16:35:16-9353.mp4").permitAll() | 117 | + .antMatchers("/api/user/login", "/index/hook/**").permitAll() |
| 115 | .anyRequest().authenticated() | 118 | .anyRequest().authenticated() |
| 116 | // 异常处理器 | 119 | // 异常处理器 |
| 117 | .and() | 120 | .and() |
| @@ -124,7 +127,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { | @@ -124,7 +127,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { | ||
| 124 | 127 | ||
| 125 | } | 128 | } |
| 126 | 129 | ||
| 127 | - CorsConfigurationSource configurationSource(){ | 130 | + CorsConfigurationSource configurationSource() { |
| 128 | // 配置跨域 | 131 | // 配置跨域 |
| 129 | CorsConfiguration corsConfiguration = new CorsConfiguration(); | 132 | CorsConfiguration corsConfiguration = new CorsConfiguration(); |
| 130 | corsConfiguration.setAllowedHeaders(Arrays.asList("*")); | 133 | corsConfiguration.setAllowedHeaders(Arrays.asList("*")); |
| @@ -135,7 +138,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { | @@ -135,7 +138,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { | ||
| 135 | corsConfiguration.setExposedHeaders(Arrays.asList(JwtUtils.getHeader())); | 138 | corsConfiguration.setExposedHeaders(Arrays.asList(JwtUtils.getHeader())); |
| 136 | 139 | ||
| 137 | UrlBasedCorsConfigurationSource url = new UrlBasedCorsConfigurationSource(); | 140 | UrlBasedCorsConfigurationSource url = new UrlBasedCorsConfigurationSource(); |
| 138 | - url.registerCorsConfiguration("/**",corsConfiguration); | 141 | + url.registerCorsConfiguration("/**", corsConfiguration); |
| 139 | return url; | 142 | return url; |
| 140 | } | 143 | } |
| 141 | 144 |
src/main/java/com/genersoft/iot/vmp/gb28181/event/alarm/AlarmEventListener.java
| 1 | package com.genersoft.iot.vmp.gb28181.event.alarm; | 1 | package com.genersoft.iot.vmp.gb28181.event.alarm; |
| 2 | 2 | ||
| 3 | +import org.jetbrains.annotations.NotNull; | ||
| 4 | +import org.slf4j.Logger; | ||
| 5 | +import org.slf4j.LoggerFactory; | ||
| 3 | import org.springframework.context.ApplicationListener; | 6 | import org.springframework.context.ApplicationListener; |
| 4 | import org.springframework.stereotype.Component; | 7 | import org.springframework.stereotype.Component; |
| 5 | -import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; | ||
| 6 | -import java.io.IOException; | ||
| 7 | -import java.util.Hashtable; | 8 | + |
| 9 | +import java.io.PrintWriter; | ||
| 8 | import java.util.Iterator; | 10 | import java.util.Iterator; |
| 9 | import java.util.Map; | 11 | import java.util.Map; |
| 10 | - | ||
| 11 | -import org.slf4j.Logger; | ||
| 12 | -import org.slf4j.LoggerFactory; | 12 | +import java.util.concurrent.ConcurrentHashMap; |
| 13 | 13 | ||
| 14 | /** | 14 | /** |
| 15 | - * @description: 报警事件监听 | ||
| 16 | - * @author: lawrencehj | ||
| 17 | - * @data: 2021-01-20 | 15 | + * 报警事件监听器. |
| 16 | + * | ||
| 17 | + * @author lawrencehj | ||
| 18 | + * @author <a href="mailto:xiaoQQya@126.com">xiaoQQya</a> | ||
| 19 | + * @since 2021/01/20 | ||
| 18 | */ | 20 | */ |
| 19 | - | ||
| 20 | @Component | 21 | @Component |
| 21 | public class AlarmEventListener implements ApplicationListener<AlarmEvent> { | 22 | public class AlarmEventListener implements ApplicationListener<AlarmEvent> { |
| 22 | 23 | ||
| 23 | - private final static Logger logger = LoggerFactory.getLogger(AlarmEventListener.class); | 24 | + private static final Logger logger = LoggerFactory.getLogger(AlarmEventListener.class); |
| 24 | 25 | ||
| 25 | - private static Map<String, SseEmitter> sseEmitters = new Hashtable<>(); | 26 | + private static final Map<String, PrintWriter> SSE_CACHE = new ConcurrentHashMap<>(); |
| 26 | 27 | ||
| 27 | - public void addSseEmitters(String browserId, SseEmitter sseEmitter) { | ||
| 28 | - sseEmitters.put(browserId, sseEmitter); | 28 | + public void addSseEmitter(String browserId, PrintWriter writer) { |
| 29 | + SSE_CACHE.put(browserId, writer); | ||
| 30 | + logger.info("SSE 在线数量: {}", SSE_CACHE.size()); | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + public void removeSseEmitter(String browserId, PrintWriter writer) { | ||
| 34 | + SSE_CACHE.remove(browserId, writer); | ||
| 35 | + logger.info("SSE 在线数量: {}", SSE_CACHE.size()); | ||
| 29 | } | 36 | } |
| 30 | 37 | ||
| 31 | @Override | 38 | @Override |
| 32 | - public void onApplicationEvent(AlarmEvent event) { | 39 | + public void onApplicationEvent(@NotNull AlarmEvent event) { |
| 33 | if (logger.isDebugEnabled()) { | 40 | if (logger.isDebugEnabled()) { |
| 34 | - logger.debug("设备报警事件触发,deviceId:" + event.getAlarmInfo().getDeviceId() + ", " | ||
| 35 | - + event.getAlarmInfo().getAlarmDescription()); | 41 | + logger.debug("设备报警事件触发, deviceId: {}, {}", event.getAlarmInfo().getDeviceId(), event.getAlarmInfo().getAlarmDescription()); |
| 36 | } | 42 | } |
| 37 | - String msg = "<strong>设备编码:</strong> <i>" + event.getAlarmInfo().getDeviceId() + "</i>" | ||
| 38 | - + "<br><strong>报警描述:</strong> <i>" + event.getAlarmInfo().getAlarmDescription() + "</i>" | ||
| 39 | - + "<br><strong>报警时间:</strong> <i>" + event.getAlarmInfo().getAlarmTime() + "</i>" | ||
| 40 | - + "<br><strong>报警位置:</strong> <i>" + event.getAlarmInfo().getLongitude() + "</i>" | ||
| 41 | - + ", <i>" + event.getAlarmInfo().getLatitude() + "</i>"; | ||
| 42 | - | ||
| 43 | - for (Iterator<Map.Entry<String, SseEmitter>> it = sseEmitters.entrySet().iterator(); it.hasNext();) { | ||
| 44 | - Map.Entry<String, SseEmitter> emitter = it.next(); | ||
| 45 | - logger.info("推送到SSE连接,浏览器ID: " + emitter.getKey()); | 43 | + |
| 44 | + String msg = "<strong>设备编号:</strong> <i>" + event.getAlarmInfo().getDeviceId() + "</i>" | ||
| 45 | + + "<br><strong>通道编号:</strong> <i>" + event.getAlarmInfo().getChannelId() + "</i>" | ||
| 46 | + + "<br><strong>报警描述:</strong> <i>" + event.getAlarmInfo().getAlarmDescription() + "</i>" | ||
| 47 | + + "<br><strong>报警时间:</strong> <i>" + event.getAlarmInfo().getAlarmTime() + "</i>"; | ||
| 48 | + | ||
| 49 | + for (Iterator<Map.Entry<String, PrintWriter>> it = SSE_CACHE.entrySet().iterator(); it.hasNext(); ) { | ||
| 50 | + Map.Entry<String, PrintWriter> response = it.next(); | ||
| 51 | + logger.info("推送到 SSE 连接, 浏览器 ID: {}", response.getKey()); | ||
| 46 | try { | 52 | try { |
| 47 | - emitter.getValue().send(msg); | ||
| 48 | - } catch (IOException | IllegalStateException e) { | ||
| 49 | - if (logger.isDebugEnabled()) { | ||
| 50 | - logger.debug("SSE连接已关闭"); | 53 | + PrintWriter writer = response.getValue(); |
| 54 | + | ||
| 55 | + if (writer.checkError()) { | ||
| 56 | + it.remove(); | ||
| 57 | + continue; | ||
| 51 | } | 58 | } |
| 52 | - // 移除已关闭的连接 | 59 | + |
| 60 | + String sseMsg = "event:message\n" + | ||
| 61 | + "data:" + msg + "\n" + | ||
| 62 | + "\n"; | ||
| 63 | + writer.write(sseMsg); | ||
| 64 | + writer.flush(); | ||
| 65 | + } catch (Exception e) { | ||
| 53 | it.remove(); | 66 | it.remove(); |
| 54 | } | 67 | } |
| 55 | } | 68 | } |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/SseController/SseController.java deleted
100755 → 0
| 1 | -package com.genersoft.iot.vmp.vmanager.gb28181.SseController; | ||
| 2 | - | ||
| 3 | -import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEventListener; | ||
| 4 | - | ||
| 5 | -import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 6 | -import org.springframework.beans.factory.annotation.Autowired; | ||
| 7 | -import org.springframework.stereotype.Controller; | ||
| 8 | -import org.springframework.web.bind.annotation.CrossOrigin; | ||
| 9 | -import org.springframework.web.bind.annotation.GetMapping; | ||
| 10 | -import org.springframework.web.bind.annotation.RequestMapping; | ||
| 11 | -import org.springframework.web.bind.annotation.RequestParam; | ||
| 12 | -import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; | ||
| 13 | - | ||
| 14 | -/** | ||
| 15 | - * @description: SSE推送 | ||
| 16 | - * @author: lawrencehj | ||
| 17 | - * @data: 2021-01-20 | ||
| 18 | - */ | ||
| 19 | -@Tag(name = "SSE推送") | ||
| 20 | - | ||
| 21 | -@Controller | ||
| 22 | -@RequestMapping("/api") | ||
| 23 | -public class SseController { | ||
| 24 | - @Autowired | ||
| 25 | - AlarmEventListener alarmEventListener; | ||
| 26 | - | ||
| 27 | - @GetMapping("/emit") | ||
| 28 | - public SseEmitter emit(@RequestParam String browserId) { | ||
| 29 | - final SseEmitter sseEmitter = new SseEmitter(0L); | ||
| 30 | - try { | ||
| 31 | - alarmEventListener.addSseEmitters(browserId, sseEmitter); | ||
| 32 | - }catch (Exception e){ | ||
| 33 | - sseEmitter.completeWithError(e); | ||
| 34 | - } | ||
| 35 | - return sseEmitter; | ||
| 36 | - } | ||
| 37 | -} |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/sse/SseController.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.gb28181.sse; | ||
| 2 | + | ||
| 3 | +import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEventListener; | ||
| 4 | +import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 5 | +import org.springframework.web.bind.annotation.GetMapping; | ||
| 6 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 7 | +import org.springframework.web.bind.annotation.RequestParam; | ||
| 8 | +import org.springframework.web.bind.annotation.RestController; | ||
| 9 | + | ||
| 10 | +import javax.annotation.Resource; | ||
| 11 | +import javax.servlet.http.HttpServletResponse; | ||
| 12 | +import java.io.IOException; | ||
| 13 | +import java.io.PrintWriter; | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * SSE 推送. | ||
| 18 | + * | ||
| 19 | + * @author lawrencehj | ||
| 20 | + * @author <a href="mailto:xiaoQQya@126.com">xiaoQQya</a> | ||
| 21 | + * @since 2021/01/20 | ||
| 22 | + */ | ||
| 23 | +@Tag(name = "SSE 推送") | ||
| 24 | +@RestController | ||
| 25 | +@RequestMapping("/api") | ||
| 26 | +public class SseController { | ||
| 27 | + | ||
| 28 | + @Resource | ||
| 29 | + private AlarmEventListener alarmEventListener; | ||
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * SSE 推送. | ||
| 33 | + * | ||
| 34 | + * @param response 响应 | ||
| 35 | + * @param browserId 浏览器ID | ||
| 36 | + * @throws IOException IOEXCEPTION | ||
| 37 | + * @author <a href="mailto:xiaoQQya@126.com">xiaoQQya</a> | ||
| 38 | + * @since 2023/11/06 | ||
| 39 | + */ | ||
| 40 | + @GetMapping("/emit") | ||
| 41 | + public void emit(HttpServletResponse response, @RequestParam String browserId) throws IOException, InterruptedException { | ||
| 42 | + response.setContentType("text/event-stream"); | ||
| 43 | + response.setCharacterEncoding("utf-8"); | ||
| 44 | + | ||
| 45 | + PrintWriter writer = response.getWriter(); | ||
| 46 | + alarmEventListener.addSseEmitter(browserId, writer); | ||
| 47 | + | ||
| 48 | + while (!writer.checkError()) { | ||
| 49 | + Thread.sleep(1000); | ||
| 50 | + writer.write(":keep alive\n\n"); | ||
| 51 | + writer.flush(); | ||
| 52 | + } | ||
| 53 | + alarmEventListener.removeSseEmitter(browserId, writer); | ||
| 54 | + } | ||
| 55 | +} |
web_src/src/layout/UiHeader.vue
| @@ -37,7 +37,6 @@ | @@ -37,7 +37,6 @@ | ||
| 37 | </template> | 37 | </template> |
| 38 | 38 | ||
| 39 | <script> | 39 | <script> |
| 40 | - | ||
| 41 | import changePasswordDialog from '../components/dialog/changePassword.vue' | 40 | import changePasswordDialog from '../components/dialog/changePassword.vue' |
| 42 | import userService from '../components/service/UserService' | 41 | import userService from '../components/service/UserService' |
| 43 | import {Notification} from 'element-ui'; | 42 | import {Notification} from 'element-ui'; |
| @@ -55,18 +54,19 @@ export default { | @@ -55,18 +54,19 @@ export default { | ||
| 55 | }; | 54 | }; |
| 56 | }, | 55 | }, |
| 57 | created() { | 56 | created() { |
| 58 | - console.log(4444) | ||
| 59 | console.log(JSON.stringify(userService.getUser())) | 57 | console.log(JSON.stringify(userService.getUser())) |
| 60 | if (this.$route.path.startsWith("/channelList")) { | 58 | if (this.$route.path.startsWith("/channelList")) { |
| 61 | this.activeIndex = "/deviceList" | 59 | this.activeIndex = "/deviceList" |
| 62 | - | ||
| 63 | } | 60 | } |
| 64 | }, | 61 | }, |
| 65 | mounted() { | 62 | mounted() { |
| 66 | window.addEventListener('beforeunload', e => this.beforeunloadHandler(e)) | 63 | window.addEventListener('beforeunload', e => this.beforeunloadHandler(e)) |
| 67 | - // window.addEventListener('unload', e => this.unloadHandler(e)) | ||
| 68 | this.alarmNotify = this.getAlarmSwitchStatus() === "true"; | 64 | this.alarmNotify = this.getAlarmSwitchStatus() === "true"; |
| 69 | - this.sseControl(); | 65 | + |
| 66 | + // TODO: 此处延迟连接 sse, 避免 sse 连接时 browserId 还未生成, 后续待优化 | ||
| 67 | + setTimeout(() => { | ||
| 68 | + this.sseControl() | ||
| 69 | + }, 3000); | ||
| 70 | }, | 70 | }, |
| 71 | methods: { | 71 | methods: { |
| 72 | loginout() { | 72 | loginout() { |
| @@ -107,10 +107,12 @@ export default { | @@ -107,10 +107,12 @@ export default { | ||
| 107 | this.sseSource = new EventSource('/api/emit?browserId=' + this.$browserId); | 107 | this.sseSource = new EventSource('/api/emit?browserId=' + this.$browserId); |
| 108 | this.sseSource.addEventListener('message', function (evt) { | 108 | this.sseSource.addEventListener('message', function (evt) { |
| 109 | that.$notify({ | 109 | that.$notify({ |
| 110 | - title: '收到报警信息', | 110 | + title: '报警信息', |
| 111 | dangerouslyUseHTMLString: true, | 111 | dangerouslyUseHTMLString: true, |
| 112 | message: evt.data, | 112 | message: evt.data, |
| 113 | - type: 'warning' | 113 | + type: 'warning', |
| 114 | + position: 'bottom-right', | ||
| 115 | + duration: 3000 | ||
| 114 | }); | 116 | }); |
| 115 | console.log("收到信息:" + evt.data); | 117 | console.log("收到信息:" + evt.data); |
| 116 | }); | 118 | }); |
web_src/src/main.js
| 1 | import Vue from 'vue'; | 1 | import Vue from 'vue'; |
| 2 | import App from './App.vue'; | 2 | import App from './App.vue'; |
| 3 | - | ||
| 4 | -Vue.config.productionTip = false; | ||
| 5 | -import ElementUI from 'element-ui'; | 3 | +import ElementUI, {Notification} from 'element-ui'; |
| 6 | import 'element-ui/lib/theme-chalk/index.css'; | 4 | import 'element-ui/lib/theme-chalk/index.css'; |
| 7 | import router from './router/index.js'; | 5 | import router from './router/index.js'; |
| 8 | import axios from 'axios'; | 6 | import axios from 'axios'; |
| 9 | import VueCookies from 'vue-cookies'; | 7 | import VueCookies from 'vue-cookies'; |
| 10 | -import echarts from 'echarts'; | ||
| 11 | import VCharts from 'v-charts'; | 8 | import VCharts from 'v-charts'; |
| 12 | 9 | ||
| 13 | import VueClipboard from 'vue-clipboard2'; | 10 | import VueClipboard from 'vue-clipboard2'; |
| 14 | -import {Notification} from 'element-ui'; | ||
| 15 | import Fingerprint2 from 'fingerprintjs2'; | 11 | import Fingerprint2 from 'fingerprintjs2'; |
| 16 | import VueClipboards from 'vue-clipboards'; | 12 | import VueClipboards from 'vue-clipboards'; |
| 17 | import Contextmenu from "vue-contextmenujs" | 13 | import Contextmenu from "vue-contextmenujs" |
| 18 | import userService from "./components/service/UserService" | 14 | import userService from "./components/service/UserService" |
| 19 | 15 | ||
| 16 | +Vue.config.productionTip = false; | ||
| 17 | + | ||
| 20 | 18 | ||
| 21 | // 生成唯一ID | 19 | // 生成唯一ID |
| 22 | Fingerprint2.get(function (components) { | 20 | Fingerprint2.get(function (components) { |
| @@ -29,10 +27,9 @@ Fingerprint2.get(function (components) { | @@ -29,10 +27,9 @@ Fingerprint2.get(function (components) { | ||
| 29 | //console.log(values) //使用的浏览器信息npm | 27 | //console.log(values) //使用的浏览器信息npm |
| 30 | // 生成最终id | 28 | // 生成最终id |
| 31 | let port = window.location.port; | 29 | let port = window.location.port; |
| 32 | - console.log(port); | ||
| 33 | const fingerPrint = Fingerprint2.x64hash128(values.join(port), 31) | 30 | const fingerPrint = Fingerprint2.x64hash128(values.join(port), 31) |
| 34 | Vue.prototype.$browserId = fingerPrint; | 31 | Vue.prototype.$browserId = fingerPrint; |
| 35 | - console.log("唯一标识码:" + fingerPrint); | 32 | + console.log("浏览器 ID: " + fingerPrint); |
| 36 | }); | 33 | }); |
| 37 | 34 | ||
| 38 | Vue.use(VueClipboard); | 35 | Vue.use(VueClipboard); |
| @@ -75,7 +72,7 @@ axios.interceptors.request.use( | @@ -75,7 +72,7 @@ axios.interceptors.request.use( | ||
| 75 | ); | 72 | ); |
| 76 | 73 | ||
| 77 | Vue.prototype.$axios = axios; | 74 | Vue.prototype.$axios = axios; |
| 78 | -Vue.prototype.$cookies.config(60*30); | 75 | +Vue.prototype.$cookies.config(60 * 30); |
| 79 | 76 | ||
| 80 | new Vue({ | 77 | new Vue({ |
| 81 | router: router, | 78 | router: router, |