axios如何利用promise无痛刷新token
目录
需求
需求解析
实现思路
方法一:
方法二:
两种方法对比
实现
封装axios基本骨架
instance.interceptors.response.use拦截实现
问题和优化
如何防止多次刷新token
同时发起两个或以上的请求时,其他接口如何重试
最后完整代码
需求
最近遇到个需求:前端登录后,后端返回token
和token有效时间
,当token过期时要求用旧token去获取新的token,前端需要做到无痛刷新token
,即请求刷新token时要做到用户无感知。
需求解析
当用户发起一个请求时,判断token是否已过期,若已过期则先调refreshToken
接口,拿到新的token后再继续执行之前的请求。
这个问题的难点在于:当同时发起多个请求,而刷新token的接口还没返回,此时其他请求该如何处理?接下来会循序渐进地分享一下整个过程。
实现思路
由于后端返回了token的有效时间,可以有两种方法:
方法一:
在请求发起前拦截每个请求,判断token的有效时间是否已经过期,若已过期,则将请求挂起,先刷新token后再继续请求。
方法二:
不在请求前拦截,而是拦截返回后的数据。先发起请求,接口返回过期后,先刷新token,再进行一次重试。
两种方法对比
方法一
- 优点: 在请求前拦截,能节省请求,省流量。
- 缺点: 需要后端额外提供一个token过期时间的字段;使用了本地时间判断,若本地时间被篡改,特别是本地时间比服务器时间慢时,拦截会失败。
PS:token有效时间建议是时间段,类似缓存的MaxAge,而不要是绝对时间。当服务器和本地时间不一致时,绝对时间会有问题。
方法二
- 优点:不需额外的token过期字段,不需判断时间。
- 缺点: 会消耗多一次请求,耗流量。
综上,方法一和二优缺点是互补的,方法一有校验失败的风险(本地时间被篡改时,当然一般没有用户闲的蛋疼去改本地时间的啦),方法二更简单粗暴,等知道服务器已经过期了再重试一次,只是会耗多一个请求。
在这里博主选择了 方法二。
实现
这里会使用axios来实现,方法一是请求前拦截,所以会使用axios.interceptors.request.use()
这个方法;
而方法二是请求后拦截,所以会使用axios.interceptors.response.use()
方法。
封装axios基本骨架
首先说明一下,项目中的token是存在localStorage
中的。request.js
基本骨架:
import axios from 'axios'// 从localStorage中获取token
function getLocalToken () {const token = window.localStorage.getItem('token')return token
}// 给实例添加一个setToken方法,用于登录后将最新token动态添加到header,同时将token保存在localStorage中
instance.setToken = (token) => {instance.defaults.headers['X-Token'] = tokenwindow.localStorage.setItem('token', token)
}// 创建一个axios实例
const instance = axios.create({baseURL: '/api',timeout: 300000,headers: {'Content-Type': 'application/json','X-Token': getLocalToken() // headers塞token}
})// 拦截返回的数据
instance.interceptors.response.use(response => {// 接下来会在这里进行token过期的逻辑处理return response
}, error => {return Promise.reject(error)
})export default instance
这个是项目中一般的axios实例的封装,创建实例时,将本地已有的token放进header,然后export出去供调用。接下来就是如何拦截返回的数据啦。
instance.interceptors.response.use拦截实现
后端接口一般会有一个约定好的数据结构,如:
{code: 1234, message: 'token过期', data: {}}
如我这里,后端约定当code === 1234
时表示token过期了,此时就要求刷新token。
instance.interceptors.response.use(response => {const { code } = response.dataif (code === 1234) {// 说明token过期了,刷新tokenreturn refreshToken().then(res => {// 刷新token成功,将最新的token更新到header中,同时保存在localStorage中const { token } = res.datainstance.setToken(token)// 获取当前失败的请求const config = response.config// 重置一下配置config.headers['X-Token'] = tokenconfig.baseURL = '' // url已经带上了/api,避免出现/api/api的情况// 重试当前请求并返回promisereturn instance(config)}).catch(res => {console.error('refreshtoken error =>', res)//刷新token失败,神仙也救不了了,跳转到首页重新登录吧window.location.href = '/'})}return response
}, error => {return Promise.reject(error)
})function refreshToken () {// instance是当前request.js中已创建的axios实例return instance.post('/refreshtoken').then(res => res.data)
}
这里需要额外注意的是,response.config
就是原请求的配置,但这个是已经处理过了的,config.url
已经带上了baseUrl
,因此重试时需要去掉,同时token也是旧的,需要刷新下。
以上就基本做到了无痛刷新token,当token正常时,正常返回,当token已过期,则axios内部进行一次刷新token和重试。对调用者来说,axios内部的刷新token是一个黑盒,是无感知的,因此需求已经做到了。
问题和优化
上面的代码还是存在一些问题的,没有考虑到多次请求的问题,因此需要进一步优化。
如何防止多次刷新token
如果refreshToken接口还没返回,此时再有一个过期的请求进来,上面的代码就会再一次执行refreshToken,这就会导致多次执行刷新token的接口,因此需要防止这个问题。我们可以在request.js
中用一个flag
来标记当前是否正在刷新token的状态,如果正在刷新则不再调用刷新token的接口。
// 是否正在刷新的标记
let isRefreshing = false
instance.interceptors.response.use(response => {const { code } = response.dataif (code === 1234) {if (!isRefreshing) {isRefreshing = truereturn refreshToken().then(res => {const { token } = res.datainstance.setToken(token)const config = response.configconfig.headers['X-Token'] = tokenconfig.baseURL = ''return instance(config)}).catch(res => {console.error('refreshtoken error =>', res)window.location.href = '/'}).finally(() => {isRefreshing = false})}}return response
}, error => {return Promise.reject(error)
})
这样子就可以避免在刷新token时再进入方法了。但是这种做法是相当于把其他失败的接口给舍弃了,假如同时发起两个请求,且几乎同时返回,第一个请求肯定是进入了refreshToken后再重试,而第二个请求则被丢弃了,仍是返回失败,所以接下来还得解决其他接口的重试问题。
同时发起两个或以上的请求时,其他接口如何重试
两个接口几乎同时发起和返回,第一个接口会进入刷新token后重试的流程,而第二个接口需要先存起来,然后等刷新token后再重试。同样,如果同时发起三个请求,此时需要缓存后两个接口,等刷新token后再重试。由于接口都是异步的,处理起来会有点麻烦。
当第二个过期的请求进来,token正在刷新,我们先将这个请求存到一个数组队列中,想办法让这个请求处于等待中,一直等到刷新token后再逐个重试清空请求队列。
那么如何做到让这个请求处于等待中呢?为了解决这个问题,我们得借助Promise
。将请求存进队列中后,同时返回一个Promise
,让这个Promise
一直处于Pending
状态(即不调用resolve),此时这个请求就会一直等啊等,只要我们不执行resolve,这个请求就会一直在等待。当刷新请求的接口返回来后,我们再调用resolve,逐个重试。最终代码:
// 是否正在刷新的标记
let isRefreshing = false
// 重试队列,每一项将是一个待执行的函数形式
let requests = []instance.interceptors.response.use(response => {const { code } = response.dataif (code === 1234) {const config = response.configif (!isRefreshing) {isRefreshing = truereturn refreshToken().then(res => {const { token } = res.datainstance.setToken(token)config.headers['X-Token'] = tokenconfig.baseURL = ''// 已经刷新了token,将所有队列中的请求进行重试requests.forEach(cb => cb(token))// 重试完了别忘了清空这个队列(掘金评论区同学指点)requests = []return instance(config)}).catch(res => {console.error('refreshtoken error =>', res)window.location.href = '/'}).finally(() => {isRefreshing = false})} else {// 正在刷新token,返回一个未执行resolve的promisereturn new Promise((resolve) => {// 将resolve放进队列,用一个函数形式来保存,等token刷新后直接执行requests.push((token) => {config.baseURL = ''config.headers['X-Token'] = tokenresolve(instance(config))})})}}return response
}, error => {return Promise.reject(error)
})
这里可能比较难理解的是requests
这个队列中保存的是一个函数,这是为了让resolve不执行,先存起来,等刷新token后更方便调用这个函数使得resolve执行。至此,问题应该都解决了
最后完整代码
import axios from 'axios'// 从localStorage中获取token
function getLocalToken () {const token = window.localStorage.getItem('token')return token
}// 给实例添加一个setToken方法,用于登录后将最新token动态添加到header,同时将token保存在localStorage中
instance.setToken = (token) => {instance.defaults.headers['X-Token'] = tokenwindow.localStorage.setItem('token', token)
}function refreshToken () {// instance是当前request.js中已创建的axios实例return instance.post('/refreshtoken').then(res => res.data)
}// 创建一个axios实例
const instance = axios.create({baseURL: '/api',timeout: 300000,headers: {'Content-Type': 'application/json','X-Token': getLocalToken() // headers塞token}
})// 是否正在刷新的标记
let isRefreshing = false
// 重试队列,每一项将是一个待执行的函数形式
let requests = []instance.interceptors.response.use(response => {const { code } = response.dataif (code === 1234) {const config = response.configif (!isRefreshing) {isRefreshing = truereturn refreshToken().then(res => {const { token } = res.datainstance.setToken(token)config.headers['X-Token'] = tokenconfig.baseURL = ''// 已经刷新了token,将所有队列中的请求进行重试requests.forEach(cb => cb(token))requests = []return instance(config)}).catch(res => {console.error('refreshtoken error =>', res)window.location.href = '/'}).finally(() => {isRefreshing = false})} else {// 正在刷新token,将返回一个未执行resolve的promisereturn new Promise((resolve) => {// 将resolve放进队列,用一个函数形式来保存,等token刷新后直接执行requests.push((token) => {config.baseURL = ''config.headers['X-Token'] = tokenresolve(instance(config))})})}}return response
}, error => {return Promise.reject(error)
})export default instance
相关文章:
axios如何利用promise无痛刷新token
目录 需求 需求解析 实现思路 方法一: 方法二: 两种方法对比 实现 封装axios基本骨架 instance.interceptors.response.use拦截实现 问题和优化 如何防止多次刷新token 同时发起两个或以上的请求时,其他接口如何重试 最后完整代…...
R语言 | 使用 ComplexHeatmap 绘制热图,分区并给对角线分区加黑边框
目的:画热图,分区,给对角线分区添加黑色边框 建议直接看0和4。 0. 准备数据 # 安装并加载必要的包 #install.packages("ComplexHeatmap") # 如果尚未安装 library(ComplexHeatmap)# 使用 iris 数据集 #data(iris)# 选择数值列&a…...
TensorFlow 简单的二分类神经网络的训练和应用流程
展示了一个简单的二分类神经网络的训练和应用流程。主要步骤包括: 1. 数据准备与预处理 2. 构建模型 3. 编译模型 4. 训练模型 5. 评估模型 6. 模型应用与部署 加载和应用已训练的模型 1. 数据准备与预处理 在本例中,数据准备是通过两个 Numpy 数…...
蓝桥杯备考:模拟算法之字符串展开
P1098 [NOIP 2007 提高组] 字符串的展开 - 洛谷 | 计算机科学教育新生态 #include <iostream> #include <cctype> #include <algorithm> using namespace std; int p1,p2,p3; string s,ret; void add(char left,char right) {string tmp;for(char ch left1;…...
[创业之路-282]:《产品开发管理-方法.流程.工具 》-1- 优秀研发体系的特征、IPD关注的4个关键要素、IPD体系的7个特点
目录 一、优秀研发体系的特征 二、IPD关注的4个关键要素 1. 组织管理 2. 市场管理 3. 流程管理 4. 产品管理 三、IPD体系的7个特点 1、产品开发是投资行为: 2、基于市场的产品研发: 3、平台化开发,大平台,小产品&#x…...
Node.js 与 PostgreSQL 集成:深入 pg 模块的应用与实践
title: Node.js 与 PostgreSQL 集成:深入 pg 模块的应用与实践 date: 2025/2/5 updated: 2025/2/5 author: cmdragon excerpt: 随着 JavaScript 在服务器端编程中的兴起,Node.js 已成为构建高性能网络应用程序的重要平台。PostgreSQL 则以其强大的特性以及对复杂数据结构的…...
【Uniapp-Vue3】从uniCloud中获取数据
需要先获取数据库对象: let db uniCloud.database(); 获取数据库中数据的方法: db.collection("数据表名称").get(); 所以就可以得到下面的这个模板: let 函数名 async () > { let res await db.collection("数据表名称…...
LeetCode 0090.子集 II:二进制枚举 / 回溯
【LetMeFly】90.子集 II:二进制枚举 / 回溯 力扣题目链接:https://leetcode.cn/problems/subsets-ii/ 给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的 子集(幂集)。 解集 不能 …...
Pytest+selenium UI自动化测试实战实例
今天来说说pytest吧,经过几周的时间学习,有收获也有疑惑,总之最后还是搞个小项目出来证明自己的努力不没有白费。 环境准备 1 确保您已经安装了python3.x 2 配置python3pycharmselenium2开发环境 3 安装pytest库pip install p…...
黑马点评 - 商铺类型缓存练习题(Redis List实现)
首先明确返回值是一个 List<ShopType> 类型那么我们修改此函数并在 TypeService 中声明 queryTypeList 方法,并在其实现类中实现此方法 GetMapping("list")public Result queryTypeList() {return typeService.queryTypeList();}实现此方法首先需要…...
C++ 创建和配置dll与lib库
C简明教程(13)创建和配置dll与lib库_怎样生成lib库和dll库-CSDN博客 C 动态库与静态库详解 一、为什么要引入库的概念 在 C 编程中,随着项目规模的不断扩大,代码量也会急剧增加。如果将所有代码都写在一个源文件中,…...
深度剖析 Veo2 工具:解锁 AI 视频创作新境界
在当下这个 AI 技术日新月异的时代,各种 AI 工具如雨后春笋般涌现,让人目不暇接。今天,我就来给大家好好说道说道谷歌旗下的 Veo2,这可是一款在 AI 视频创作领域相当有分量的工具。好多朋友都在问,Veo2 到底厉害在哪?好不好上手?能在哪些地方派上用场?别着急,今天我就…...
LabVIEW自定义测量参数怎么设置?
以下通过一个温度采集案例,说明在 LabVIEW 中设置自定义测量参数的具体方法: 案例背景 假设使用 NI USB-6009 数据采集卡 和 热电偶传感器 监测温度,需自定义以下参数: 采样率:1 kHz 输入量程:0~10 V&a…...
JVM执行流程与架构(对应不同版本JDK)
直接上图(对应JDK8以及以后的HotSpot) 这里主要区分说明一下 方法区于 字符串常量池 的位置更迭: 方法区 JDK7 以及之前的版本将方法区存放在堆区域中的 永久代空间,堆的大小由虚拟机参数来控制。 JDK8 以及之后的版本将方法…...
数据治理项目为什么沦为了PPT工程?
数据治理项目为什么沦为了PPT工程? 数据治理项目为什么沦为PPT工程数据治理项目面临的深层挑战数据治理项目的破局之道 "这个项目明明做了快一年了,怎么感觉还在原地踏步?"数据治理小张最近很烦恼。 整天泡在会议室里,写…...
module ‘matplotlib.cm‘ has no attribute ‘get_cmap‘
目录 解决方法1: 解决方法2,新版api改了: module matplotlib.cm has no attribute get_cmap 报错代码: cmap matplotlib.cm.get_cmap(Oranges) 解决方法1: pip install matplotlib3.7.3 解决方法2,新版…...
HTML5 教程之标签(3)
HTML5 <center> 标签 (已废弃) 定义和用法 <center> 标签对其包围的文本进行水平居中处理。HTML5不支持使用<center>标签,因此有关该标签的更多信息,请参考“HTML <center>标签”部分! 示例: <center>这个…...
告别传统办公软件,这款编辑器让你事半功倍!
文章目录 1 界面的多样性2 性能优化3 文档编辑器的新功能4 外部文本支持5 体验感想 ONLYOFFICE最近发布了文档8.2版本,带来了众多新特性和性能改进。作为一名用户和开发者,我对这些更新进行了深入的体验,感受到了不少亮点。 新版本特别强调了…...
AI协助探索AI新构型自动化创新的技术实现
一、AI自进化架构的核心范式 1. 元代码生成与模块化重构 - 代码级自编程:基于神经架构搜索的强化学习框架,AI可通过生成元代码模板(框架的抽象层定义、神经元结点-网络拓扑态的编码抽象定义)自动组合功能模块。例如࿰…...
全能型免费内网穿透工具,全面支持macOS、Windows、Linux及Docker系统
1. 登陆官网网址并注册帐号 ngrok | API Gateway, Kubernetes Networking Secure Tunnels 2 下载并安装工具 3. 启动工具 在命令行执行 ngrok http http://localhost:8080 其中端口可换成用户自己想要穿透的端口 4. 获取穿透地址 命令执行后会出现如下画面,红…...
Web - CSS3浮动定位与背景样式
概述 这篇文章主要介绍了 CSS3 中的浮动定位、背景样式、变形效果等内容。包括 BFC 规范与创建方法、浮动的功能与使用要点、定位的多种方式及特点、边框与圆角的设置、背景的颜色、图片等属性、多种变形效果及 3D 旋转等,还提到了浏览器私有前缀。 BFC规范与浏览…...
VUE之组件通信(二)
1、v-model v-model的底层原理:是:value值和input事件的结合 $event到底是啥?啥时候能.target 对于原生事件,$event就是事件对象 ,能.target对应自定义事件,$event就是触发事件时,所传递的数据ÿ…...
Gauss高斯:建表语法,存储方式,OLTP和OLAP,系统时间,数组,分组(grouping set,rollup)
数据库和表的语法 数据库 表 oracle,高斯, hive的默认存储方式都是列式存储 存储方式 高斯数据库(GaussDB)支持列式存储和行式存储 OLTP 与 OLAP OLTP(联机事务处理,Online Transaction Processing)是一种用于管理…...
Java基础进阶
Java基础进阶 异常 概述 异常就是程序出现了不正常的情况 具体分为:Throwable—>(Error Exception);Exception—>(RuntimeException 非RuntimeException) Throwable类是Java语言中所有错误和异常的祖宗类;(上面还有Object类) Thr…...
【数据结构】链表应用1
链表应用 面试题 02.02.返回倒数第k个节点题目描述思路解题过程复杂度 查找相同后缀题目描述解题思路完整代码: 删除绝对值相等的节点题目描述解题思路代码 面试题 02.02.返回倒数第k个节点 题目描述 实现一种算法,找出单向链表中倒数第 k 个节点。返回…...
python gltf生成预览图
使用Python生成GLTF模型的预览图 随着3D技术的不断发展,GLTF(GL Transmission Format)逐渐成为了Web和移动应用程序中最流行的3D文件格式之一。GLTF文件不仅能以较小的体积存储复杂的3D模型,还支持动画、材质、光照和纹理等特性。…...
HTTP和HTTPS协议详解
HTTP和HTTPS协议详解 HTTP详解什么是http协议http协议的发展史http0.9http1.0http1.1http2.0 http协议的格式URI和URL请求request响应response http协议完整的请求与响应流程 HTTPS详解为什么使用HTTPSSSL协议HTTPS通信过程TLS协议 HTTP详解 什么是http协议 1、全称Hyper Tex…...
实战:利用百度站长平台加速网站收录
本文转自:百万收录网 原文链接:https://www.baiwanshoulu.com/33.html 利用百度站长平台加速网站收录是一个实战性很强的过程,以下是一些具体的步骤和策略: 一、了解百度站长平台 百度站长平台是百度为网站管理员提供的一系列工…...
专门记录台式电脑常见问题
1、蓝屏死机,检查内存硬盘和cpu 2、拆内存条,用橡皮擦金手指 3、放主板静电,扣主板电池 4、系统时间不正确,主板电池没电 5、开机键坏了 6、电脑主机的风扇转,正常通电运行,但显示器没信号。看键盘的num键&…...
数据库系统概念第六版记录 一
1.关系型数据库 关系型数据库(Relational Database,简称 RDB)是基于关系模型的一种数据库,它通过表格的形式来组织和存储数据。每个表由若干行(记录)和列(字段)组成,数据…...
本地Ollama部署DeepSeek R1模型接入Word
目录 1.本地部署DeepSeek-R1模型 2.接入Word 3.效果演示 4.问题反馈 上一篇文章办公新利器:DeepSeekWord,让你的工作更高效-CSDN博客https://blog.csdn.net/qq_63708623/article/details/145418457?spm1001.2014.3001.5501https://blog.csdn.net/qq…...
Meta Sapiens AI论文解读:人类视觉模型基石初现,AI 未来走向何方?
一、引言 在本文中,我们将深入探讨 Meta AI 的一项新成果,该成果发表于一篇题为《Sapiens:人类视觉模型的基础》的研究论文中。这篇论文介绍了一系列模型,这些模型针对四项以人类为中心的基本任务,正如我们在上面的演示…...
输入类控件和多元素控件【QT】
文章目录 输入类控件QLineEdit Text EditCombo BoxSpin BoxDialSlider多元素控件QListWidget TableWidetTreeWidgetQGroupBoxTab Widget# QVBoxLayout# QHBoxLayoutQGridLayoutQFormLayout 输入类控件 QLineEdit 例如: 实现一个用户输入姓名 密码 电话 性别 的功能…...
一键开启/关闭deepseek
一键开启/关闭 Deepseek对应下载的模型一键开启 Deepseek,一键关闭Deepseek双击对应的bat,就可以启动https://mbd.pub/o/bread/Z56YmpZvbat 下载:https://mbd.pub/o/bread/Z56YmpZv 可以自己写下来,保存成bat文件,也可…...
gitea - fatal: Authentication failed
文章目录 gitea - fatal: Authentication failed概述run_gitea_on_my_pkm.bat 笔记删除windows凭证管理器中对应的url认证凭证启动gitea服务端的命令行正常用 TortoiseGit 提交代码备注END gitea - fatal: Authentication failed 概述 本地的git归档服务端使用gitea. 原来的用…...
Spring AI 智能体通过 MCP 集成本地文件数据
作者:刘军 Model Context Protocol(MCP)简介 模型上下文协议(即 Model Context Protocol,MCP) [ 1] 是一个开放协议,它规范了应用程序如何向大型语言模型(LLM)提供上下…...
音视频入门基础:RTP专题(5)——FFmpeg源码中,解析SDP的实现
一、引言 FFmpeg源码中通过ff_sdp_parse函数解析SDP。该函数定义在libavformat/rtsp.c中: int ff_sdp_parse(AVFormatContext *s, const char *content) {const char *p;int letter, i;char buf[SDP_MAX_SIZE], *q;SDPParseState sdp_parse_state { { 0 } }, *s1…...
MyBatis XML文件配置
目录 一、 配置连接字符串和MyBatis 二、书写持久层代码 2.1 添加Mapper接口 2.2 添加UserlnfoXMLMapper.xml 三、增删改查 3.1 、增(Insert) 3.2、删(Delete) 3.3、改 (Update) 3.4、查 (Select) MyBatisXML的方式需要以下两步&am…...
【Leetcode 热题 100】1143. 最长公共子序列
问题背景 给定两个字符串 t e x t 1 text_1 text1 和 t e x t 2 text_2 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 0 0。 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变…...
【算法】动态规划专题④ ——LCS(最长公共子序列)+ LPS(最长回文子序列) python
目录 前置知识LCS举一反三LPS 前置知识 【算法】动态规划专题③ ——二维DP python 子序列定义为: 不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。 LCS 最长公共子序列 https://www.lanqiao.cn/problems/1189/learning/?p…...
Cesium点集中获取点的id,使用viewer.value.entities.getById报错的解决方法
错误代码: viewer.value.entities.getById(pickedObject.id) 报错: 可以正常获取movement.position但是一直出现如下报错,无法获得航点的id,通过断点定位为 viewer.value.entities.getById(pickedObject.id)导致的报错 解决方…...
360手机刷机 360手机解Bootloader 360手机ROOT
360手机刷机 360手机解Bootloader 360手机ROOT 问:360手机已停产,现在和以后,能刷机吗? 答:360手机,是肯定能刷机的 360手机资源下载网站 360手机-360手机刷机RootTwrp 360os.top 360rom.github.io 一、…...
深度探索DeepSeek-R1:AI大模型的本地应用与个人知识库构建
深度探索DeepSeek-R1:AI大模型的本地应用与个人知识库构建 引言 在当今这个信息爆炸的时代,如何高效地存储、处理和获取知识,已经成为每个人面临的挑战。想象一下,如果你能在没有互联网连接的情况下,构建一个属于自己…...
LabVIEW图像采集与应变场测量系统
开发了一种基于LabVIEW的图像采集与应变场测量系统,提供一种高精度、非接触式的测量技术,用于监测物体的全场位移和应变。系统整合了实时监控、数据记录和自动对焦等功能,适用于工程应用和科学研究。 项目背景 传统的位移和应变测量技术往往…...
解决DeepSeek服务器繁忙问题:本地部署与优化方案
deepseek服务器崩了,手把手教你如何在手机端部署一个VIP通道! 引言 随着人工智能技术的快速发展,DeepSeek等大语言模型的应用越来越广泛。然而,许多用户在使用过程中遇到了服务器繁忙、响应缓慢等问题。本文将探讨如何通过本地部…...
今日AI和商界事件(2025-02-05)
今日AI领域的相关事件主要包括以下几个方面: 一、DeepSeek引发全球关注 性能与成本优势: DeepSeek推出的R1模型性能出色,成本较低,在全球AI行业引发震动。该模型在数学、代码处理等方面性能优异,受到广泛赞誉。 平台…...
SQL 秒变 ER 图 sql转er图
🚀SQL 秒变 ER 图,校园小助手神了! 学数据库的宝子们集合🙋♀️ 是不是每次碰到 SQL 转 ER 图就头皮发麻?看着密密麻麻的代码,脑子直接死机,好不容易理清一点头绪,又被复杂的表关…...
SQL server 创建DB Link 详解
在日常工作中,经常涉及到跨库操作,为使跨数据库的操作变得更加灵活高效,我们可以在 SQL Server 中建立数据库链接( DB Link),实现 SQL Server 数据库与其他数据库(如 Oracle, MySQL 等ÿ…...
25.2.5学习记录
今天主要学的是哈希表的理论知识,但是都是c实现,C语言的代码实现还没有完全搞明白。 在写题的时候,懵懂的学着正确代码,用C语言模拟实现哈希表去解题。 在哈希表的理论知识中,学到哈希函数,了解哈希冲突产…...
C# List 列表综合运用实例⁓Hypak原始数据处理编程小结
C# List 列表综合运用实例⁓Hypak原始数据处理编程小结 1、一个数组解决很麻烦引出的问题1.1、RAW 文件尾部数据如下:1.2、自定义标头 ADD 或 DEL 的数据结构如下: 2、程序 C# 源代码的编写和剖析2.1、使用 ref 关键字,通过引用将参数传递,以…...