“UniApp的音频播放——点击视频进入空白+解决视频播放器切换视频时一直加载的问题”——video.js、video-js.css

       今天,又解决了一个单子“UniApp的音频播放——点击视频进入空白+解决视频播放器切换视频时一直加载的问题”


一、问题描述

在开发一个基于 video.js 的视频播放器时,用户通过上下滑动切换视频时,视频一直处于加载状态,无法正常播放。通过日志可以看到,视频源地址和索引更新是正确的,但视频无法播放。具体表现为:

  1. 视频加载卡住:切换视频时,播放器一直显示加载动画,无法播放视频。

  2. 日志显示正常:日志中显示的视频源地址和索引更新是正确的,例如:

    即将更新视频源为: http://127.0.0.1:8000/media/m3u8/30bd5d2225919b1724ca69d07633beb1/index.m3u8
    currentIndex: 1
    videos长度: 4
  3. 播放器未正确响应:尽管视频源地址更新了,但播放器未能正确加载和播放新视频。


 二、问题复现步骤

  1. 初始化播放器:加载第一个视频,播放器正常工作。

  2. 滑动切换视频:用户通过上下滑动切换到下一个视频。

  3. 视频加载卡住:播放器显示加载动画,但视频无法播放。

  4. 日志输出:日志显示视频源地址和索引更新正确,但播放器未响应。


    三、来请看代码,各位客官

<template><!-- <view@click="handleVideoClick"@touchstart="handleTouchStart"@touchmove="handleTouchMove"@touchend="handleTouchEnd"> --><!--  根据 isAdVideo 的值决定显示广告视频还是常规视频 --><!-- 对于广告视频,不显示控制条,自动播放 --><!-- <video v-if="isAdVideo" :src="videoSrc" :controls="false" autoplay></video> --><!-- 对于常规视频,显示控制条,自动播放 --><!-- <video v-else :src="videoSrc" controls autoplay></video> --><!-- </view> -->
<view><div id="app"><div class="video-js" ref="videos"></div></div>
</view>
</template><script>import { baseUrl } from '@/common/api.js'
export default {data() {return {// 存储当前视频文件的路径videoSrc: '',// 标记当前视频是否为广告视频isAdVideo: false,// 存储广告的 URLadUrl: '',// 存储当前视频在视频列表中的索引currentIndex: 0,// 存储所有视频的数组videos: [],// 存储触摸开始时的 Y 坐标touchStartY: 0,// 存储触摸结束时的 Y 坐标touchEndY: 0,// video.js 的播放器实例player: null,};},onLoad(options) {// 从传入的参数中获取视频文件路径const videoFile = options.videoFile;// 判断是否为广告视频,将字符串 'true' 转换为布尔值const isAd = options.isAd === 'true';// 从传入的参数中获取广告 URL,并进行解码const adUrl = options.adUrl? decodeURIComponent(options.adUrl) : '';// 从传入的参数中获取视频列表,并将其从 JSON 字符串转换为数组const videos = options.videos? JSON.parse(decodeURIComponent(options.videos)) : [];// 将视频文件路径存储到 data 中,修改错误点 1// this.videoFile = videoFile;// 将是否为广告视频的状态存储到 data 中this.isAdVideo = isAd;// 将广告 URL 存储到 data 中this.adUrl = adUrl;// 将视频列表存储到 data 中this.videos = videos;// 根据是否为广告视频来确定视频源的路径if (isAd) {// 假设广告视频的文件名直接作为参数传递,提取文件名const adVideoPath = `${videoFile}`;console.log('1111',adVideoPath);// 拼接完整的广告视频源路径this.videoSrc = `${baseUrl}${adVideoPath}`;} else {// 对于常规视频,在视频列表中查找匹配的视频文件const video = videos.find(v => {console.log('当前视频的 m3u8_url:', v.m3u8_url);  // 打印每个视频的 m3u8_urlreturn v.m3u8_url === videoFile;});console.log('222',videoFile);// const video = videos.find(v => v.m3u8_url === videoFile);// console.log('222',v =>v.m3u8_url,videoFile);if (video) {// 拼接完整的常规视频源路径this.videoSrc = `${baseUrl}${video.m3u8_url}`;} else {// 如果未找到对应的视频文件,打印错误信息并退出方法console.error('未找到对应的视频文件路径');return;}}// 查找当前视频在视频列表中的索引this.currentIndex = this.videos.findIndex(v => {if (this.isAdVideo) {const asa =v.ad && v.ad.m3u8_url === videoFile;// 对于广告视频,通过广告视频文件查找索引console.log('当前视频的 vad:', v.ad.m3u8_url,asa);console.log('videoFile',videoFile)return asa ;}// 对于常规视频,通过常规视频文件查找索引return v.m3u8_url === videoFile;});console.log('this.videoFile',videos.find(v => v.m3u8_url === videoFile).m3u8_url);// 打印初始的视频文件路径console.log('Initial video file:', this.videoSrc);},
// beforeDestroy() {
// 	var playerElement = document.getElementById('video');
// 	var player = videojs.getInstance(playerElement);
// 	if (player) {
// 	 player.dispose();
// 	 } // },mounted() {this.initplayer();},beforeDestroy() {// 使用 $refs 来查找 video 元素const videoElement = this.$refs.videos.querySelector('video');if (videoElement) {const player = videojs.getPlayer(videoElement);if (player) {console.log('播放器正在销毁');player.dispose();} else {console.log('未找到播放器实例,可能未初始化');}} else {console.log('未找到 video 元素');}},methods: {initplayer(){// const videoElement = this.$refs.videos.querySelector('video');// const player = videojs.getPlayer(videoElement);// player.dispose();// if (this.player) {//         // 如果播放器已经初始化,直接设置新的视频源//         this.player.src({ src: this.videoSrc, type: 'application/x-mpegURL' });//         this.player.play();//         return;//       }let video = document.createElement('video');video.id = 'video';// video.style = 'width: 100%; height: 100%;';// video.controls = true;video.preload = "auto"video.setAttribute('playsinline', true) //IOS微信浏览器支持小窗内播放video.setAttribute('webkit-playsinline', true) //这个bai属性是ios 10中设置可以让视频在小du窗内播放,也就是不是全zhi屏播放的video标签的一个属性video.setAttribute('x5-video-player-type', 'h5') //安卓 声明启用同层H5播放器 可以在video上面加东西// const ada='http://127.0.0.1:8000/media\\m3u8\\caba10d1b61e5f2aa1e068bebeb55663\\index.m3u8';let source = document.createElement('source');// source.src = ada;source.src = this.videoSrc;video.appendChild(source);// returnthis.$refs.videos.appendChild(video);let that = this;let player = this.$video('video', {autoDisable: true,preload: 'none', //auto - 当页面加载后载入整个视频 meta - 当页面加载后只载入元数据 none - 当页面加载后不载入视频language: 'zh-CN',fluid: true, // 自适应宽高muted: false, //  是否静音aspectRatio: '16:9', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")controls: true, //是否拥有控制条 【默认true】,如果设为false ,那么只能通过api进行控制了。也就是说界面上不会出现任何控制按钮autoplay: false, //如果true,浏览器准备好时开始回放。 autoplay: "muted", // //自动播放属性,muted:静音播放loop: true, // 导致视频一结束就重新开始。 视频播放结束后,是否循环播放controlBar: {volumePanel: { //声音样式inline: true // 不使用水平方式},timeDivider: true, // 时间分割线durationDisplay: true, // 总时间progressControl: true, // 进度条remainingTimeDisplay: true, //当前以播放时间fullscreenToggle: true, //全屏按钮pictureInPictureToggle: false, //画中画}}, function() {this.on('error', function(err) { //请求数据时遇到错误console.log("请求数据时遇到错误", err)});this.on('stalled', function(stalled) { //网速失速console.log("网速失速", stalled)});});},// 处理触摸开始事件,记录触摸开始时的 Y 坐标handleTouchStart(event) {this.touchStartY = event.touches[0].clientY;},// 处理触摸移动事件,目前不做任何处理,可添加优化逻辑handleTouchMove(event) {// 例如,可以添加代码防止快速滑动时的抖动效果},// 处理触摸结束事件,记录触摸结束时的 Y 坐标,并调用 handleSwipe 方法handleTouchEnd(event) {this.touchEndY = event.changedTouches[0].clientY;this.handleSwipe();},// 处理滑动操作handleSwipe() {// 计算触摸的垂直距离const distance = this.touchEndY - this.touchStartY;// 如果滑动距离小于 30 像素,不进行任何操作if (Math.abs(distance) < 30) {return;}// 如果滑动距离大于 0,表示向下滑动,调用 handleSwipeDown 方法if (distance > 0) {this.handleSwipeDown();} else {// 否则表示向上滑动,调用 handleSwipeUp 方法this.handleSwipeUp();}},// 处理向上滑动,切换到下一个视频handleSwipeUp() {// 如果不是最后一个视频if (this.currentIndex < this.videos.length - 1) {// 增加当前视频索引this.currentIndex++;// 更新视频信息this.updateVideo();// 打印下一个视频的文件路径console.log('Swipe Up: Next video file:', this.videoSrc);// 打印是否为广告视频console.log('是否广告', this.isAdVideo);} else {// 已到达最后一个视频,打印提示信息console.log("已经是最后一个视频了");}},// 处理向下滑动,切换到上一个视频handleSwipeDown() {// 如果不是第一个视频if (this.currentIndex > 0) {// 减小当前视频索引this.currentIndex--;// 更新视频信息this.updateVideo();// 打印上一个视频的文件路径console.log('Swipe Down: Previous video file:', this.videoSrc);} else {// 已到达第一个视频,打印提示信息console.log("已经是第一个视频了");}},// 更新视频信息,包括视频源和广告 URLupdateVideo() {// 获取当前索引对应的下一个视频const nextVideo = this.videos[this.currentIndex];console.log('11111', this.videos, nextVideo, this.currentIndex);// 判断下一个视频是否为广告视频this.isAdVideo =!!nextVideo.ad;if (this.isAdVideo) {// 如果是广告视频,更新视频源为广告视频源并打印console.log('1111:', nextVideo.ad.m3u8_url);this.videoSrc = `${baseUrl}${nextVideo.ad.m3u8_url}`;} else {// 如果是常规视频,更新视频源为常规视频源并打印this.videoSrc = `${baseUrl}${nextVideo.m3u8_url}`;console.log('2222:', nextVideo.m3u8_url);}// 根据是否为广告视频更新广告 URL,修改错误点 3if (this.isAdVideo) {this.adUrl = nextVideo.ad.urll;} else {this.adUrl = '';}// 当视频源更新时,更新播放器的 srcif (this.player) {this.player.src({ src: this.videoSrc });}},// 处理视频点击事件handleVideoClick() {// 如果是广告视频且有广告 URLif (this.isAdVideo && this.adUrl) {// 根据不同的平台,使用不同的跳转方式打开广告 URLif (process.env.VUE_APP_PLATFORM === 'h5') {// 在 H5 平台使用 window.open 打开广告 URLwindow.open(this.adUrl, '_blank');} else {// 在小程序或其他平台使用 uni.navigateTo 进行跳转uni.navigateTo({url: `/pages/webview/webview?url=${encodeURIComponent(this.adUrl)}`});}}}}
};
</script>

三、可能的原因

  1. 视频源路径格式问题

    • 视频路径中使用了反斜杠 \,例如:http://127.0.0.1:8000\media\m3u8\30bd5d2225919b1724ca69d07633beb1\index.m3u8

    • 反斜杠在某些环境下可能导致路径解析错误。

  2. 播放器未正确销毁和重新初始化

    • 在切换视频时,旧的播放器实例可能未正确销毁,导致新的播放器实例无法正常初始化。

  3. 视频加载超时或失败

    • 视频文件可能无法加载,或者加载时间过长,导致播放器一直处于加载状态。

  4. 用户交互限制

    • 某些浏览器要求视频播放必须在用户交互后触发,如果未正确处理用户交互,可能导致视频无法播放。

  5. 播放器初始化问题

    • 播放器初始化逻辑中,this.$video 未定义,可能导致播放器无法正确初始化。

  6. 广告视频逻辑问题

    • 广告视频的逻辑中,nextVideo.ad.urll 拼写错误,导致广告 URL 无法正确更新。


 四、问题分析

1. 视频路径格式问题

  • 问题:视频路径中使用了反斜杠 \,例如:http://127.0.0.1:8000\media\m3u8\30bd5d2225919b1724ca69d07633beb1\index.m3u8

  • 影响:在某些环境下,反斜杠可能导致路径解析错误,视频无法加载。

  • 解决方案:将反斜杠替换为正斜杠 /

this.videoSrc = `${baseUrl}${videoFile}`.replace(/\\/g, '/');

2. 播放器未正确销毁和重新初始化

  • 问题:在切换视频时,旧的播放器实例可能未正确销毁,导致新的播放器实例无法正常初始化。

  • 影响:切换视频时,播放器可能卡在加载状态或无法播放。

  • 解决方案:在切换视频时,销毁旧的播放器实例并重新初始化新的播放器实例。

updateVideo() {const nextVideo = this.videos[this.currentIndex];this.isAdVideo = !!nextVideo.ad;if (this.isAdVideo) {this.videoSrc = `${baseUrl}${nextVideo.ad.m3u8_url}`.replace(/\\/g, '/');} else {this.videoSrc = `${baseUrl}${nextVideo.m3u8_url}`.replace(/\\/g, '/');}this.adUrl = this.isAdVideo ? nextVideo.ad.url : '';console.log('即将更新视频源为:', this.videoSrc);this.destroyPlayer(); // 销毁旧的播放器实例this.$nextTick(() => {this.initplayer(); // 重新初始化播放器});
}

3. 视频加载超时或失败

  • 问题:视频文件可能无法加载,或者加载时间过长,导致播放器一直处于加载状态。

  • 影响:用户可能会看到视频一直加载,无法播放。

  • 解决方案:设置超时机制,防止长时间停留在加载状态。

    async updateVideoSource() {if (!this.player) return;console.log('正在更新视频源:', this.videoSrc);try {this.player.pause(); // 暂停当前播放this.player.src({ src: this.videoSrc, type: 'application/x-mpegURL' });this.player.load();// 监听 loadeddata 事件,确保视频数据加载完成后再尝试播放this.player.one('loadeddata', () => {console.log('视频数据加载完成');this.isPlaying = false;this.player.play().then(() => {this.isPlaying = true;}).catch(error => {console.error('播放失败:', error);});});// 设置一个超时机制,防止长时间停留在加载状态const timeoutId = setTimeout(() => {console.warn('视频加载超时');// 尝试重新加载视频this.player.src({ src: this.videoSrc, type: 'application/x-mpegURL' });this.player.load();}, 10000); // 10秒超时// 当视频加载完成时清除超时this.player.on('loadeddata', () => clearTimeout(timeoutId));} catch (error) {console.error('更新视频源并准备播放失败:', error);}
    }

    4. 用户交互限制

  • 问题:某些浏览器要求视频播放必须在用户交互后触发,如果未正确处理用户交互,可能导致视频无法播放。

  • 影响:视频无法自动播放,用户需要手动点击播放按钮。

  • 解决方案:在用户交互后触发视频播放。

handleTouchEnd(event) {this.touchEndY = event.changedTouches[0].clientY;this.handleSwipe();this.isUserInteracted = true; // 标记用户交互if (this.player && this.isUserInteracted) {this.player.play().catch(error => {console.error('播放失败:', error);});}
}

5. 播放器初始化问题

  • 问题:播放器初始化逻辑中,this.$video 未定义,可能导致播放器无法正确初始化。

  • 影响:播放器无法正常工作。

  • 解决方案:使用 videojs 直接初始化播放器。

    initplayer() {let video = document.createElement('video');video.id = 'video';video.preload = "auto";video.setAttribute('playsinline', true);video.setAttribute('webkit-playsinline', true);video.setAttribute('x5-video-player-type', 'h5');let source = document.createElement('source');source.src = this.videoSrc;video.appendChild(source);this.$refs.videos.appendChild(video);this.player = videojs(video, {autoplay: false,controls: !this.isAdVideo,sources: [{ src: this.videoSrc, type: 'application/x-mpegURL' }]});this.player.on('error', (error) => {console.error('视频加载错误:', error);});
    }

    6. 播放器销毁问题

  • 问题:在 beforeDestroy 钩子中,播放器销毁逻辑可能无法正确执行。

  • 影响:播放器实例可能未正确销毁,导致内存泄漏。

  • 解决方案:确保播放器实例被正确销毁。

    beforeDestroy() {if (this.player) {console.log('播放器正在销毁');this.player.dispose();this.player = null;} else {console.log('未找到播放器实例,可能未初始化');}
    }

    7. 日志输出不足

  • 问题:日志输出较少,难以定位问题。

  • 影响:调试困难。

  • 解决方案:在关键步骤添加日志输出。

    console.log('即将更新视频源为:', this.videoSrc);
    console.log('currentIndex:', this.currentIndex);
    console.log('videos长度:', this.videos.length);

    8. 广告视频逻辑问题

  • 问题:广告视频的逻辑中,nextVideo.ad.urll 拼写错误。

  • 影响:广告 URL 无法正确更新。

  • 解决方案:修正拼写错误。

    if (this.isAdVideo) {this.adUrl = nextVideo.ad.url; // 修正拼写错误
    } else {this.adUrl = '';
    }

  • 五、完整代码

  • <template><view @touchstart="handleTouchStart" @touchmove="handleTouchMove" @touchend="handleTouchEnd"><!-- 视频容器 --><div id="app"><div class="video-js" ref="videos"></div></div></view>
    </template><script>
    import { baseUrl } from '@/common/api.js';
    import videojs from 'video.js';
    import 'video.js/dist/video-js.css'; // 引入默认样式export default {name: 'VideoPlayer',data() {return {videoSrc: '',isAdVideo: false,adUrl: '',currentIndex: 0,videos: [],touchStartY: 0,touchEndY: 0,player: null, // video.js 的播放器实例uniqueKey: Date.now(), // 用于强制刷新组件isPlaying: false, // 跟踪播放状态isUserInteracted: false, // 跟踪用户交互状态};},onLoad(options) {this.initFromOptions(options);},activated() {// 当组件被激活时(从缓存中恢复),重新初始化播放器this.$nextTick(() => this.initplayer());},deactivated() {// 当组件被停用时(进入缓存),销毁播放器this.destroyPlayer();},mounted() {// 确保在挂载时初始化播放器this.$nextTick(() => this.initplayer());},methods: {async initFromOptions(options) {const videoFile = options.videoFile;const isAd = options.isAd === 'true';const adUrl = options.adUrl ? decodeURIComponent(options.adUrl) : '';const videos = options.videos ? JSON.parse(decodeURIComponent(options.videos)) : [];this.isAdVideo = isAd;this.adUrl = adUrl;this.videos = videos;if (isAd) {this.videoSrc = `${baseUrl}${videoFile}`.replace(/\\/g, '/');} else {const video = videos.find(v => v.m3u8_url === videoFile);if (video) {this.videoSrc = `${baseUrl}${video.m3u8_url}`.replace(/\\/g, '/');} else {console.error('未找到对应的视频文件路径');return;}}this.currentIndex = this.videos.findIndex(v => {if (this.isAdVideo) {return v.ad && v.ad.m3u8_url === videoFile;}return v.m3u8_url === videoFile;});console.log('Initial video file:', this.videoSrc);await this.initplayer(); // 确保播放器初始化完成},async initplayer() {// 如果播放器已经存在,则更新源而不是重新创建if (this.player) {await this.updateVideoSource();return;}let videoElement = document.createElement('video');videoElement.id = 'video';videoElement.preload = "auto";videoElement.setAttribute('playsinline', true);videoElement.setAttribute('webkit-playsinline', true);videoElement.setAttribute('x5-video-player-type', 'h5');let source = document.createElement('source');source.src = this.videoSrc;videoElement.appendChild(source);this.$refs.videos.appendChild(videoElement);// 使用 Vue 的 nextTick 方法确保 DOM 更新完成后才初始化 Video.js 播放器this.$nextTick(() => {this.player = videojs(videoElement,{autoplay: false,controls: !this.isAdVideo,sources: [{ src: this.videoSrc, type: 'application/x-mpegURL' }]},async function onPlayerReady() {console.log("播放器已准备好");try {if (this.isUserInteracted) {await this.play(); // 使用 async/await 确保 play() 完成}} catch (error) {console.error('播放失败:', error);}}.bind(this));// 监听错误事件this.player.on('error', (error) => {console.error('视频加载错误:', error);console.error('错误详情:', this.player.error()); // 获取详细的错误信息});});},destroyPlayer() {if (this.player) {console.log('播放器正在销毁');this.player.dispose();this.player = null; // 清除 player 实例引用} else {console.log('未找到播放器实例,可能未初始化');}},async updateVideoSource() {if (!this.player) return;console.log('正在更新视频源:', this.videoSrc);try {this.player.pause(); // 暂停当前播放this.player.src({ src: this.videoSrc, type: 'application/x-mpegURL' });this.player.load();// 监听 loadeddata 事件,确保视频数据加载完成后再尝试播放this.player.one('loadeddata', () => {console.log('视频数据加载完成');this.isPlaying = false;this.player.play().then(() => {this.isPlaying = true;}).catch(error => {console.error('播放失败:', error);// 可以在这里添加重试逻辑或提示用户});});// 设置一个超时机制,防止长时间停留在加载状态const timeoutId = setTimeout(() => {console.warn('视频加载超时');// 尝试重新加载视频this.player.src({ src: this.videoSrc, type: 'application/x-mpegURL' });this.player.load();}, 10000); // 10秒超时// 当视频加载完成时清除超时this.player.on('loadeddata', () => clearTimeout(timeoutId));} catch (error) {console.error('更新视频源并准备播放失败:', error);// 可以在这里添加重试逻辑或提示用户}},handleTouchStart(event) {this.touchStartY = event.touches[0].clientY;},handleTouchMove(event) {// 这里可以添加优化逻辑,但目前保持原样},handleTouchEnd(event) {this.touchEndY = event.changedTouches[0].clientY;this.handleSwipe();this.isUserInteracted = true; // 标记用户交互if (this.player && this.isUserInteracted) {this.player.play().catch(error => {console.error('播放失败:', error);});}},handleSwipe() {const distance = this.touchEndY - this.touchStartY;if (Math.abs(distance) < 30) return;if (distance > 0) {this.handleSwipeDown();} else {this.handleSwipeUp();}},handleSwipeUp() {if (this.currentIndex < this.videos.length - 1) {this.currentIndex++;this.updateVideo();console.log('Swipe Up: Next video file:', this.videoSrc);console.log('是否广告', this.isAdVideo);} else {console.log("已经是最后一个视频了");}},handleSwipeDown() {if (this.currentIndex > 0) {this.currentIndex--;this.updateVideo();console.log('Swipe Down: Previous video file:', this.videoSrc);} else {console.log("已经是第一个视频了");}},updateVideo() {const nextVideo = this.videos[this.currentIndex];this.isAdVideo = !!nextVideo.ad;if (this.isAdVideo) {this.videoSrc = `${baseUrl}${nextVideo.ad.m3u8_url}`.replace(/\\/g, '/');} else {this.videoSrc = `${baseUrl}${nextVideo.m3u8_url}`.replace(/\\/g, '/');}this.adUrl = this.isAdVideo ? nextVideo.ad.url : '';console.log('即将更新视频源为:', this.videoSrc); // 添加日志输出console.log('currentIndex:', this.currentIndex); // 添加日志输出console.log('videos长度:', this.videos.length); // 添加日志输出this.destroyPlayer(); // 销毁旧的播放器实例this.$nextTick(() => {this.initplayer(); // 重新初始化播放器});},handleVideoClick() {if (this.isAdVideo && this.adUrl) {if (process.env.VUE_APP_PLATFORM === 'h5') {window.open(this.adUrl, '_blank');} else {uni.navigateTo({url: `/pages/webview/webview?url=${encodeURIComponent(this.adUrl)}`});}}}},watch: {// 监听路由变化并强制刷新组件$route(to, from) {this.uniqueKey = Date.now(); // 改变 key 来强制刷新组件this.$nextTick(() => this.initplayer()); // 确保播放器在路由变化后重新初始化}}
    };
    </script><style scoped>
    /* 添加样式 */
    #app {width: 100%;height: 100%;
    }
    .video-js {width: 100%;height: 100%;
    }
    </style>


  • 总结

    通过修复视频路径格式、确保播放器正确销毁和重新初始化、处理视频加载超时、确保用户交互后播放、修正播放器初始化逻辑以及修正广告视频逻辑,可以有效解决视频切换时一直加载的问题。如果问题仍然存在,建议进一步检查视频源的有效性和网络状态,并使用浏览器的开发者工具查看网络请求和错误日志。

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

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

相关文章

[Python学习日记-78] 基于 TCP 的 socket 开发项目 —— 模拟 SSH 远程执行命令

[Python学习日记-78] 基于 TCP 的 socket 开发项目 —— 模拟 SSH 远程执行命令 简介 项目分析 如何执行系统命令并拿到结果 代码实现 简介 在Python学习日记-77中我们介绍了 socket 基于 TCP 和基于 UDP 的套接字&#xff0c;还实现了服务器端和客户端的通信&#xff0c;本…

AIGC视频生成模型:Meta的Emu Video模型

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细介绍Meta的视频生成模型Emu Video&#xff0c;作为Meta发布的第二款视频生成模型&#xff0c;在视频生成领域发挥关键作用。 &#x1f33a;优质专栏回顾&am…

IO进程----进程

进程 什么是进程 进程和程序的区别 概念&#xff1a; 程序&#xff1a;编译好的可执行文件 存放在磁盘上的指令和数据的有序集合&#xff08;文件&#xff09; 程序是静态的&#xff0c;没有任何执行的概念 进程&#xff1a;一个独立的可调度的任务 执行一个程序分配资…

flutter 使用google_mlkit_image_labeling做图片识别

在AI横行的如今&#xff0c;相信大家或多或少都做过跟AI接轨的需求了吧&#xff1f;今天我说的是关于图片识别的需求&#xff0c;flutter的专属图片识别插件google_mlkit_image_labeling。 google_mlkit_image_labeling它是Google旗下的Google Cloud Vision API中分支出来的一部…

elasticsearch基础

分布式搜索引擎01 1. 初始elasticsearch 1.1. 了解ES 1.1.1. elasticsearch的作用 elasticsearch是一款非常强大的开源搜索引擎&#xff0c;具备非常多强大功能&#xff0c;可以帮助我们从海量数据中快速找到需要的内容 例如&#xff1a; 在github搜索代码&#xff1a; 在电…

SQL Server查询计划操作符——查询计划相关操作符(4)

7.3. 查询计划相关操作符 28)Declare:该操作符在查询计划中分配一个本地变量。该操作符是一个语言元素。该操作符具体如图7.2-28所示。 图 7.2-28 查询计划操作符Declare示例 29)Delete:该操作符从一个对象中删除满足其参数列中可选谓词的数据行。该操作符具体如图7.2-29…

C++的auto_ptr智能指针:从诞生到被弃用的历程

C作为一种功能强大的编程语言&#xff0c;为开发者提供了众多便捷的特性和工具&#xff0c;其中智能指针是其重要特性之一。智能指针能够自动管理内存&#xff0c;有效避免内存泄漏等常见问题。然而&#xff0c;并非所有智能指针都尽善尽美&#xff0c;auto_ptr便是其中的一个例…

[手机Linux] 七,NextCloud优化设置

安装完成后在个人设置里发现很多警告&#xff0c;一一消除。 只能一条一条解决了。 关于您的设置有一些错误。 1&#xff0c;PHP 内存限制低于建议值 512 MB。 设置php配置文件&#xff1a; /usr/local/php/etc/php.ini 把里面的&#xff1a; memory_limit 128M 根据你自…

微软宣布Win11 24H2进入新阶段!设备将自动下载更新

快科技1月19日消息&#xff0c;微软于1月16日更新了支持文档&#xff0c;宣布Windows 11 24H2进入新阶段。 24H2更新于2024年10月1日发布&#xff0c;此前为可选升级&#xff0c;如今微软开始在兼容的Windows 11设备上自动下载并安装24H2版本。 微软表示&#xff1a;“运行Wi…

ddl-auto: create

package com.test.entity;import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.Comment;import java.time.Instant; import java.util.Objects;Comment("操作日志表") Entity // Entity注解的类将会初始化为一张数据库表 Table(name …

循环队列(C语言)

从今天开始我会开启一个专栏leetcode每日一题&#xff0c;大家互相交流代码经验&#xff0c;也当作我每天练习的自我回顾。第一天的内容是leetcode622.设计循环队列。 一、题目详细 设计你的循环队列实现。 循环队列是一种线性数据结构&#xff0c;其操作表现基于 FIFO&#…

Golang Gin系列-1:Gin 框架总体概述

本文介绍了Gin框架&#xff0c;探索了它的关键特性&#xff0c;并建立了简单入门的应用程序。在这系列教程里&#xff0c;我们会探索Gin的主要特性&#xff0c;如路由、中间件、数据库集成等&#xff0c;最终能使用Gin框架构建健壮的web应用程序。 总体概述 Gin是Go编程语言的…

在线宠物用品|基于vue的在线宠物用品交易网站(源码+数据库+文档)

|在线宠物用品交易网站 目录 基于springbootvue的在线宠物用品交易网站 一、前言 二、系统设计 三、系统功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道师&am…

鸿蒙安装HAP时提示“code:9568344 error: install parse profile prop check error” 问题现象

在启动调试或运行应用/服务时&#xff0c;安装HAP出现错误&#xff0c;提示“error: install parse profile prop check error”错误信息。 解决措施 该问题可能是由于应用使用了应用特权&#xff0c;但应用的签名文件发生变化后未将新的签名指纹重新配置到设备的特权管控白名…

图像去雾数据集的下载和预处理操作

前言 目前&#xff0c;因为要做对比实验&#xff0c;收集了一下去雾数据集&#xff0c;并且建立了一个数据集的预处理工程。 这是以前我写的一个小仓库&#xff0c;我决定还是把它用起来&#xff0c;下面将展示下载的路径和数据处理的方法。 下面的代码均可以在此找到。Auo…

React的应用级框架推荐——Next、Modern、Blitz等,快速搭建React项目

在 React 企业级应用开发中&#xff0c;Next.js、Modern.js 和 Blitz 是三个常见的框架&#xff0c;它们提供了不同的特性和功能&#xff0c;旨在简化开发流程并提高应用的性能和扩展性。以下是它们的详解与比较&#xff1a; Next、Modern、Blitz 1. Next.js Next.js 是由 Ve…

内网渗透测试工具及渗透测试安全审计方法总结

1. 内网安全检查/渗透介绍 1.1 攻击思路 有2种思路&#xff1a; 攻击外网服务器&#xff0c;获取外网服务器的权限&#xff0c;接着利用入侵成功的外网服务器作为跳板&#xff0c;攻击内网其他服务器&#xff0c;最后获得敏感数据&#xff0c;并将数据传递到攻击者&#xff0…

Weblogic - General - 弱口令 任意文件读取漏洞

0x01&#xff1a;漏洞简介 首先需要说明&#xff0c;本文并不是介绍了 Weblogic 某一 CVE 漏洞&#xff0c;而是提供了一种通用的测试思路。 0x0101&#xff1a;弱口令漏洞 弱口令漏洞主要是由于用户安全意识淡薄&#xff0c;为了便于记忆&#xff0c;设置了强度过低的密码&…

重温STM32之环境安装

缩写 CMSIS&#xff1a;common microcontroller software interface standard 1&#xff0c;keil mdk安装 链接 Keil Product Downloads 安装好后&#xff0c;开始安装平台软件支持包&#xff08;keil 5后不在默认支持所有的平台软件开发包&#xff0c;需要自行下载&#…

Ceph与RAID在存储中的协同工作过程

本文将结合架构图&#xff0c;详细讲解Ceph与RAID如何在存储环境中相互配合&#xff0c;共同提供高效且可靠的存储服务。 架构概述 从上图中可以看到&#xff0c;Ceph的架构主要分为四个层次&#xff1a; 客户端和服务接口层&#xff1a;这一层包括客户端访问存储应用的接口…