如果朋友走上了错误的人生道路,就算破坏友情也要阻止他
们将在这个小小的城镇中相互扶持,共同生活下去
今宵之月,绝不西沉。只此美梦,不再苏醒。从今往后,生生世世,长相厮守,为你立誓。
我们不能让这次冒险之旅没有意义没有收获
我们的本质就是血,一层层地重复,然后世代脉脉相传的血才是黑血的真实
当你知道自己被爱著的时候就不会自卑了asd
不要哭,我还没有努力到要哭的程度,不甘心就可以了das
既不回头,何必不忘;既然无缘,何必誓言;今日种种,似水无痕
空谈之类,是谈不久,也谈不出什么来的,它终必被事实的镜子照出原形,拖出尾巴而去
只愿涤荡四方,护得一世之隅。
你看你浪费了多少流星,哈哈……不牵个手也很浪费这样的夜晚呢
有形的东西迟早会凋零,但只有回忆是永远不会凋零的
已经无法回来的东西,得到和舍弃都很痛苦
Pain past is pleasure.11222
我因为后来离开村子,在远处看见这一村庄人的火焰。看见他们比熄灭还要寂静的那一场燃烧。我像一根逃出火堆的干柴,幸运而孤独地站在远处。
首页
统计
免费Chat GPT
关于
更多
友链
每日新闻
视频
高清壁纸
Search
1
2023彩虹易支付最新原版开源网站源码,完整的易支付源码,无后门
466 阅读
2
ThinkPHP6的常见问题解答
388 阅读
3
Spring Boot之七牛云分片上传
241 阅读
4
小狐狸ChatGPT付费创作系统V2.4.9独立版 +WEB端+ H5端 + 小程序端(支持分享朋友圈、破解弹窗)
230 阅读
5
国内最好用的六款虚拟机软件
213 阅读
技术分享
源码分享
课程分享
号卡套餐
移动专区
电信专区
联通专区
广电专区
软件仓库
电脑软件
安卓软件
活动线报
值得一看
Search
标签搜索
技术分享
源码
源码分享
css
安卓软件
活动线报
软件
课程分享
号卡
电脑软件
PHP
值得一看
HTML
js
教程
chatgpt
AI
小程序
ThinkPHP
联通
老K博客
累计撰写
421
篇文章
累计收到
339
条评论
今日撰写
0
篇文章
首页
栏目
技术分享
源码分享
课程分享
号卡套餐
移动专区
电信专区
联通专区
广电专区
软件仓库
电脑软件
安卓软件
活动线报
值得一看
页面
统计
免费Chat GPT
关于
友链
每日新闻
视频
高清壁纸
用户登录
登录
搜索到
117
篇与
的结果
2024-05-31
大文件切片上传优化,子线程计算文件hash,pLimit库并发控制上传
效果演示: 生成hash无论是客户端还是服务端,都要用到文件和切片的 hash,生成 hash 最简单的方法是 文件名 + 切片下标,但是如果文件名一旦修改,生成的 hash 就会失效。事实上只要文件内容不变, hash 就不应该变化,所以我们根据文件内容生成 hash。这里我们选用 spark-md5库,它可以根据文件内容计算出文件的hash值。imort SparkMD5 from 'spark-md5.min.js' /** * 生成文件hash */ const chunkHash = async () => { message.innerText = "生成hash开始" // 生成文件hash开始 const hash = await getFileHash(chunksList)// 生成文件hash message.innerText = hash // 显示hash值 return hash } /** * * 获取全部文件内容hash * @param {any} fileList */ async function getFileHash(fileList) { const spark = new SparkMD5.ArrayBuffer() const result = fileList.map((item, key) => getFileContent(item)) try { const contentList = await Promise.all(result) for (let i = 0; i < contentList.length; i++) { spark.append(contentList[i]) } return spark.end() // 返回hash总值 } catch (e) { console.log(e) } } /** * * 获取全部文件内容 * @param {any} file:Blob * @returns */ function getFileContent(file) { return new Promise((resolve, reject) => { const fileReader = new FileReader() //读取文件内容 fileReader.readAsArrayBuffer(file) fileReader.onload = e => { resolve(e.target.result) } fileReader.onerror = e => { reject(fileReader.error) fileReader.abort() } }) }如果上传的文件过大时,读取文件内容计算hash非常耗时,并且会引起 UI 阻塞,导致页面假死,所以我们使用 web-worker 在 worker 线程计算 hash,这样仍可以在主界面正常做交互。( web-worker 使用方式不清楚的参考MDN介绍)具体做法如下:/** * 生成hash */ const calculateHash = (fileList) => { message.innerText = "计算hash..."; return new Promise((resolve, reject) => { window.w = new Worker('../js/setMd5.js') // 接收子线程内容 window.w.onmessage = ev => { message.innerText = ""; resolve(ev.data) w.terminate() // 停止子线程 } // 发生错误,终止子线程 window.w.onerror = err => { w.terminate() reject(error) console.log(error.filename, error.lineno, error.message) // 发生错误的文件名、行号、错误内容 } // 发送信息 window.w.postMessage(fileList) }) }setMd5.js文件:// 引入spaprk-md5库 self.importScripts('./spark-md5.min.js') //接受主进程发送过来的数据 self.onmessage = function (e) { const fileChunkList = e.data getFileHash(fileChunkList) .then(hash => { self.postMessage({ hash: hash, }) }) .catch(() => { self.postMessage({ error: 'crate hash error', }) }) } /** * * 获取全部文件内容hash * @param {any} fileList */ async function getFileHash(fileList) { const spark = new SparkMD5.ArrayBuffer() const result = fileList.map((item, key) => getFileContent(item)) try { const contentList = await Promise.all(result) for (let i = 0; i < contentList.length; i++) { spark.append(contentList[i]) } return spark.end() } catch (e) { console.log(e) } } /** * * 获取全部文件内容 * @param {any} file * @returns */ function getFileContent(file) { return new Promise((resolve, reject) => { const fileReader = new FileReader() //读取文件内容 fileReader.readAsArrayBuffer(file) fileReader.onload = e => { resolve(e.target.result) } fileReader.onerror = e => { reject(fileReader.error) fileReader.abort() } }) } 流程图hash值+索引号命名切片在切片上传uploadChunks方法中调用生成文件hash代码得到hash值,将hash值+索引号作为切片名字上传.并发控制切片上传并发控制具体实现我们在"面试官:为什么网盘上传多个视频文件不能一起上传,80%人回答不清楚!"一文中有详细介绍,可以通过自己封装并发控制函数实现,也可以使用pLimit库实现。/** * 限制多个并发任务,只能同时执行maxCount个 * maxCount: 最大并发数 */ function harexsLimit(maxCount) { let activeCount = 0 // 激活任务数 let waitTask = [] // 任务队列 const execute = (asyncFn, ...args) => { return new Promise((resolve, reject) => { const task = create(asyncFn, args, resolve, reject) if (activeCount >= maxCount) { waitTask.push(task) } else { task() } }) } /** * 创建待执行任务 */ const create = (asyncFn, args, resolve, reject) => { return () => { asyncFn(...args).then(resolve).catch(reject).finally(() => { activeCount-- // 每执行完一个任务启动任务任务队列下个任务 if (waitTask.length) { waitTask.shift()() //执行任务 } }) activeCount++ } } return execute }总结大文件切片生成hash时,如果文件过大,hash值计算会比较慢,还有一种方式就是计算抽样 Hash,减少计算的字节数可以大幅度减少耗时;在前文的代码中,我们是将大文件切片后,全量传入 spark-md5.min.js 中来根据文件的二进制内容计算文件的 hash 的。那么,举个例子,我们可以这样优化: 文件切片以后,取第一个和最后一个切片全部内容,其他切片的取首中尾 三个地方各2各字节来计算 hash。这样来计算文件 hash 会快很多。
2024年05月31日
22 阅读
0 评论
0 点赞
2024-05-31
消息推送技术,除了websocket还知道那些?
websocketWebSocket是一种网络通信协议,它提供了在单个TCP连接上进行全双工通信的能力。这意味着数据可以在客户端和服务器之间双向流动,而无需客户端通过轮询或重复请求来获取更新。WebSocket的使用场景:实时游戏:WebSocket可以用于实现在线多人游戏的实时交互。聊天应用:即时通讯和聊天室可以通过WebSocket实现实时消息传递。股票行情:实时股票交易平台可以利用WebSocket推送最新的市场数据。协作工具:在线文档编辑或实时绘图工具等协作平台可以使用WebSocket来同步用户操作。WebSocket技术实现聊天应用:客户端实现创建WebSocket连接:使用new WebSocket(url)构造函数创建一个新的WebSocket对象,其中url是WebSocket服务器的地址。设置事件处理程序:为WebSocket对象设置各种事件处理程序,如onopen、onmessage、onerror和onclose。发送消息:当WebSocket连接成功建立后(即onopen事件触发时),客户端可以通过调用send方法发送消息。接收消息:当服务器发送消息时(即onmessage事件触发时),客户端可以接收消息。关闭连接:当不再需要WebSocket连接时,可以调用close方法关闭连接。示例代码(HTML + JavaScript):<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>WebSocket Chat Example</title> <script> // 当文档加载完毕时执行 document.addEventListener('DOMContentLoaded', function() { var ws; var chatBox = document.getElementById('chatBox'); var messageInput = document.getElementById('messageInput'); var sendButton = document.getElementById('sendButton'); // 尝试连接到WebSocket服务器 function connect() { ws = new WebSocket("ws://localhost:8080"); ws.onopen = function() { console.log('WebSocket 连接成功'); }; ws.onmessage = function(event) { console.log('收到消息:', event.data); chatBox.textContent += event.data + '\n'; }; ws.onerror = function(error) { console.error('WebSocket 出现错误:', error); }; ws.onclose = function() { console.log('WebSocket 连接关闭'); }; } // 发送消息 function sendMessage() { if (ws.readyState === WebSocket.OPEN) { ws.send(messageInput.value); messageInput.value = ''; } else { console.error('WebSocket 连接未建立'); } } // 绑定按钮点击事件 sendButton.onclick = function() { sendMessage(); }; // 自动连接WebSocket connect(); }); </script> </head> <body> <h1>WebSocket Chat</h1> <pre id="chatBox"></pre> <input type="text" id="messageInput"> <button id="sendButton">发送</button> </body> </html>服务器端实现服务器端的实现会依赖于你选择的后端技术。以下是使用Node.js和ws库的一个简单示例:示例代码(Node.js + ws):const WebSocket = require('ws'); const server = new WebSocket.Server({ port: 8080 }); server.on('connection', function(socket) { console.log('新客户端已连接'); // 监听客户端发送的消息 socket.on('message', function(message) { console.log('收到消息:', message); // 将收到的消息广播给所有客户端 server.clients.forEach(function(client) { if (client.readyState === WebSocket.OPEN) { client.send(message); } }); }); socket.on('close', function() { console.log('客户端已断开连接'); }); });在这个例子中,服务器会监听8080端口上的WebSocket连接。每当有新消息时,它将消息广播给所有连接的客户端。这个简单的实例展示了WebSocket如何实现客户端和服务器之间的实时双向通信。轻量级推送技术SSEServer-Sent Events(SSE)是一种允许服务器向浏览器推送实时数据的技术。它是基于HTTP协议的,并且是一种轻量级的解决方案,适用于服务器到客户端的单向通信。以下是关于SSE的一些关键点:工作原理SSE利用HTTP连接来实现服务器到客户端的单向通信。一旦客户端通过EventSource接口连接到服务器,服务器就可以发送数据到客户端。客户端接收到数据后,默认会触发message事件。特点基于HTTP:SSE使用标准的HTTP协议,因此易于实现和部署。单向通信:SSE主要用于服务器向客户端的单向数据推送,不支持客户端向服务器的推送。轻量级:与WebSocket相比,SSE更简单,不需要复杂的握手过程。自动重连:如果连接断开,SSE会自动尝试重连。文本数据:SSE主要推送文本数据,对于二进制数据需要进行编码。使用场景实时更新:如股票价格、体育比赛得分等。社交媒体:实时显示好友动态、消息通知等。新闻网站:实时推送新闻头条。在线游戏:推送游戏状态更新。数据格式SSE 协议非常简单,正常的Http请求,更改请起头相关配置即可Content-Type: text/event-stream,utf-8 Cache-Control: no-cache Connection: keep-alive发送的文本流,用UTF8格式编码。文本事件流的消息由两个换行符分开,以冒号开头的为注释行,会被忽略。文本流字段event: 用于标识事件类型的字符串,如果没有指定 event ,浏览器默认认为是 message 。data: 消息的数据字段,当 EventSource 收到多个 data: 开头的连续行时,会将它们连接起来,在它们之间插入一个换行符。末尾的换行符也会被删除。id: 事件ID,会被设置为当前 EventSource 对象的内部属性“最后一个事件ID”的值。retry: 重新连接的时间。如果与服务器的连接丢失,浏览器会等待指定的时间,然后重新连接。 retry 必须是一个整数,它的单位是毫秒。 实现服务器端服务器端使用express框架创建一个持久的HTTP连接,并在有新数据时发送数据到客户端。数据通常以纯文本格式发送,并且每条消息之间以一对换行符分隔。const express = require('express') //引用框架 const app = express() //创建服务 const port = 8088 //项目启动端口 //设置跨域访问 app.all('*', function (req, res, next) { //设置允许跨域的域名,*代表允许任意域名跨域 res.header('Access-Control-Allow-Origin', '*') //允许的header类型 res.header( 'Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With' ) //跨域允许的请求方式 res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS') // 可以带cookies res.header('Access-Control-Allow-Credentials', true) if (req.method == 'OPTIONS') { res.sendStatus(200) } else { next() } }) app.get('/sse', (req, res) => { res.set({ 'Content-Type': 'text/event-stream', //设定数据类型 'Cache-Control': 'no-cache', // 长链接拒绝缓存 'Connection': 'keep-alive', //设置长链接 }) console.log('进入到长连接了') //持续返回数据 setInterval(() => { console.log('正在持续返回数据中ing') const data = { message: `当前时间: ${new Date().toLocaleTimeString()}`, } res.write(`data: ${JSON.stringify(data)}\n\n`) }, 1000) // 当客户端断开连接时,清理资源 req.on('close', () => { clearInterval() // 清除定时器 res.end() // 结束响应 }) }) //创建项目 app.listen(port, () => { console.log(`项目启动成功-http://localhost:${port}`) }) 客户端客户端使用EventSource接口来接收服务器推送的数据。以下是一个基本的客户端实现示例:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <ul id="ul"> </ul> </body> <script> //生成li元素 function createLi(data) { let li = document.createElement("li"); li.innerHTML = String(data.message); return li; } //判断当前浏览器是否支持SSE let source = '' if (!!window.EventSource) { source = new EventSource('http://localhost:8088/sse/'); } else { throw new Error("当前浏览器不支持SSE") } //对于建立链接的监听 source.onopen = function (event) { console.log(source.readyState); console.log("长连接打开"); }; //对服务端消息的监听 source.onmessage = function (event) { console.log(JSON.parse(event.data)); console.log("收到长连接信息"); let li = createLi(JSON.parse(event.data)); document.getElementById("ul").appendChild(li) }; //对断开链接的监听 source.onerror = function (event) { console.log(source.readyState); console.log("长连接中断"); }; </script> </html>总结在数字化时代,信息的即时传递变得至关重要。实时消息推送技术作为连接用户与服务的重要桥梁,使得信息能够迅速、准确地传递给用户。无论是社交媒体的通知、新闻更新、还是应用内的消息提醒,实时消息推送技术都扮演着不可或缺的角色。
2024年05月31日
12 阅读
0 评论
0 点赞
2024-05-30
如何在无停机的情况下更新Docker容器
要在无停机的情况下更新Docker容器,您可以使用以下步骤:通过构建新的Docker镜像来更新容器。您可以在Dockerfile中添加所需的更改并构建新的镜像。使用新的镜像创建一个新的容器。您可以使用docker run命令来创建一个新的容器,并指定要使用的新镜像。将新容器与旧容器连接。您可以使用Docker网络功能来连接新容器与旧容器,以确保数据和连接不中断。将流量逐渐转移到新容器。您可以使用负载均衡器或其他工具逐渐将流量从旧容器转移到新容器,直到所有流量都已经转移到新容器。关闭旧容器。一旦所有流量都已经转移到新容器,您可以安全地关闭旧容器,并且更新过程完成。通过以上步骤,您可以在无停机的情况下更新Docker容器,确保您的服务持续在线并且不中断。
2024年05月30日
9 阅读
0 评论
0 点赞
2024-05-30
如何在Foundation框架中使用NSAttributedSubstringFromRange方法
在Foundation框架中,我们可以使用 NSAttributedSubstringFromRange 方法来从一个 NSAttributedString 对象中获取指定范围的子字符串。例如,假设我们有一个 NSAttributedString 对象 attributedString ,我们想要获取该对象中从位置 startIndex 开始,长度为 length 的子字符串,可以使用如下代码:NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:@"Hello World" attributes:@{NSForegroundColorAttributeName: [UIColor blackColor]}]; NSInteger startIndex = 6; NSInteger length = 5; NSAttributedString *subString = [attributedString attributedSubstringFromRange:NSMakeRange(startIndex, length)];在上面的例子中, subString 将会是一个包含World这个子字符串的 NSAttributedString 对象。我们可以继续使用该对象进行其他操作,比如设置不同的属性或者将其显示在界面上。
2024年05月30日
32 阅读
0 评论
0 点赞
2024-05-30
如何在Laravel中实现自定义的错误监控和警报通知
要在Laravel中实现自定义的错误监控和警报通知,你可以使用Laravel自带的Exception Handler来捕获和处理异常。你可以在app/Exceptions/Handler.php文件中定义自定义的异常处理逻辑。以下是一个简单的示例,演示如何在Laravel中捕获异常并发送邮件通知:public function report(Exception $exception) { if ($this->shouldReport($exception)) { // 发送邮件通知 \Mail::raw($exception->getMessage(), function ($message) { $message->to('admin@example.com')->subject('Error occurred'); }); } parent::report($exception); }在上面的示例中,我们在report方法中检查是否应该报告异常,然后使用Mail类发送邮件通知。你可以根据自己的需求定制通知的内容和接收者。另外,你也可以使用第三方服务,如Sentry、Bugsnag等来实现更高级的错误监控和警报通知功能。这些服务提供了更丰富的功能和更方便的集成方式,可以根据自己的需求选择合适的解决方案。
2024年05月30日
22 阅读
0 评论
0 点赞
1
...
7
8
9
...
24
CC BY-NC-ND