axios 封装 http 请求详解
前言
Axios 是一个基于 Promise 的 HTTP 库,它的概念及使用方法本文不过多赘述,请参考:axios传送门
本文重点讲述下在项目中是如何利用 axios 封装 http 请求。
一、预设全局变量
在 /const/preset.js 中配置预先设置一些全局变量
window.$env = process.env.NODE_ENV === 'development' ? 'DEV' : 'PROD'// 默认开发环境
let config = {baseURL: location.origin,httpBaseURL: location.origin + '/api',webBaseURL: location.origin + location.pathname,vipAddress: '/necp/mapp/sc', // 后端微服务的统一入口
}// 生产环境
if (window.$env !== 'DEV') {if (location.href.indexOf('/ecs/') > -1) {config.baseURL = location.href.replace(/\/ecs.+/, '')config.httpBaseURL = config.baseURL}
}// 文件资源请求路径
config.fileUrl = config.httpBaseURL + config.vipAddress + 'file/download'window.$globals = config
在 main.js 中引入
import Vue from 'vue'
import './const/preset'
// ...
// 把 vue 示例挂载到 window 下
window.$vm = new Vue({render: h => h(App),router
}).$mount('#app')
因为生产环境部署的差异,http 请求的 baseURL 并非都是统一的,所以不单独配置默认的 axios.defaults.baseURL,而是通过此文件预设的变量进行设置。
全局预设变量中的 config.httpBaseURL 将添加到请求的 URL 中,对于代码中的 location.href.indexOf(‘/ecs/’) > -1 判断只是举例,可根据实际需求决定是否需要。
二、http 请求封装
1.配置全局 axios 默认值
axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8'
axios.defaults.timeout = 60000
axios.defaults.crossDomain = true
此三条配置分别对应以下作用:
- 发送POST请求时,设置请求头的 Content-Type 字段为 ‘application/json;charset=UTF-8’ ,以便服务器正确解析请求的数据。
- 发送请求默认的超时时间为 60s。
- 允许跨域请求。
提示:覆盖默认超时时间,可在 axios 发送请求的参数 config 对象中设置 timeout 属性即可
2.配置请求拦截器
请求拦截器是在发送请求前执行的函数,它可以用于修改请求的配置或者在请求发送前进行一些操作。最常用的功能就是使用请求拦截器实现身份验证。
一个常见的实现是用户登录之后,服务端会响应用户的登录信息,并且把用户的身份认证 token 存储到 cookie 中,然后在请求拦截器中将 cookie 中获取到的 token 设置到请求头中,每次发送请求都会携带上此 token 发送到服务端,服务端再获取请求头的 token 来判断用户是否登录状态或者登录已过期,作出不同的响应。
axios.interceptors.request.use(config => {const token = cookie.get(TOKEN_COOKIE_KEY)if (token) {config.headers[TOKEN_REQ_KEY] = token}return config},error => {return Promise.reject(error)}
)
3.配置响应拦截器
响应拦截器是在接收到响应后执行的函数,它可以用于修改响应的数据或者在接收到响应后进行一些操作。
响应拦截器主要作用包括修改响应数据、错误处理、统一处理响应等功能,因把响应数据及错误的处理都放在了发送请求的回调中,所以只定义了最简单的响应拦截器。
axios.interceptors.response.use(response => {return response
}, error => {return Promise.reject(error)
})
4.发送请求的 request 函数
此函数接收四个参数:请求方法,请求的 api 接口,请求参数,请求的 config 配置项,返回一个 Promise 的实例。此函数完成了正常响应处理、异常处理、重复请求取消等功能。
4.1 拼接完整的请求 url
const apiInterceptor = api => {if (api.startsWith('http')) { // 自定义请求路径return api.slice(4)}if (api.startsWith('_SC_')) { // 项目统一的api前缀api = $globals.vipAddress + api.slice(4)}return $globals.httpBaseURL + api
}const request = async (method = 'post', api, params = {}, config = {}) => {// 省略...let url = apiInterceptor(api)let opts = {method,url,headers: config.headers || {},withCredentials: config.withCredentials || true // 跨域请求时是否需要使用凭证}// 省略...
}
调用 apiInterceptor 函数来拼接完整的请求 url,如果 api 是以 http 开头,则表示自定义 api 的请求路径,否则请求路径使用 preset.js 中预设的全局变量来拼接完整的 url。
4.2 参数处理
const jsonObj2FormData = jsonObj => {let formData = new FormData()Object.keys(jsonObj).forEach(key => {if (jsonObj[key] instanceof Array) {formData.append(key, JSON.stringify(jsonObj[key]))} else {formData.append(key, jsonObj[key])}})return formData
}
// 省略...if (config.formDataFormat) {opts.headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'params = jsonObj2FormData(params)
}
if (method == 'post') {opts.data = params
} else {opts.params = params
}
- 服务端有部分接口接收的参数要求 FormData 格式,这时候需要将参数序列化,并且修改请求头的 Content-Type。
- 发送 get/post 请求时,接收参数的对象的 key 不一样。
4.3 正常响应处理
使用 axios(opts) 发起请求,得到的是一个 Promise,在 then 的第一个参数中传入一个正常的响应处理函数,这个函数接收响应拦截器中返回的 response 作为参数。
return new Promise((resolve, reject) => {axios(opts).then(response => {let res = response.dataif (config.customHandler) { // 自定义响应处理if (config.responseAll) return resolve(response)return resolve(res)}if (res) {if (res.code === 000) { // 登录超时$vm.$toast.error(res.message)$vm.$store.dispatch('REMOVE_USER') // 移除 cookie、session、storage 存储的信息reject(res.message)if (window.self === window.top) {$vm.$router.push('/login') // 跳转登录页}} else if (res.code === 200) {resolve(res.data)} else {$vm.$toast.error(res.message || '接口异常, 请稍后重试')reject(res)}} else {$vm.$toast.error('接口无返回内容')}})
})
提示:$vm 指向全局的 Vue 实例,$toast 则是将 element 的 Message 组件实例挂载到了 Vue 的原型上
- 如果调用 request 函数传入了
config.customHandler = true
,表示自定义响应处理,并且config.responseAll = true
时,会把响应拦截器中得到的 response 直接返回,这个参数主要用于调用服务端响应字节流的接口时使用。 - 后端响应的数据结构如下图,并且登录过期接口的 http 响应状态码是 200,但是响应的数据格式中的 code 值为特定值,所以要特殊处理此类情况,清空存储在客户端的客户信息,跳转到登录页。
- 当响应的数据中与服务端约定响应正常的 code 为 200,此时把 data 作为 Promise.resolve 的值
4.4 异常处理
异常处理在 axios(opts).then() 的第二个参数中传入处理函数,这个函数接收响应拦截器中返回的 Promise.reject(error) 作为参数。
异常处理主要针对 http 响应状态码不等于 200 的情况,包括常见的请求超时,404请求资源不存在,50X 服务器异常等情况。
axios(opts).then(response => {// 省略...
}, error => {// 如果自定义处理if (config.customHandler) {reject(error)return}// 请求超时if (error.code == 'ECONNABORTED' && error.message.indexOf('timeout') > -1) {$vm.$toast.error(`请求超时,接口地址:${url}`)reject(error)return}if (error.response) {// 401未登录或登录失效if (error.response.status === 401) {reject(error)if (window.self === window.top) {$vm.$router.push('/login')}return}switch (error.response.status) {case 404:$vm.$toast.error(`请求的资源不存在,异常服务接口地址:${url}`)breakcase 408:$vm.$toast.error('请求超时')breakcase 500:$vm.$toast.error('服务异常')breakcase 502:$vm.$toast.error(error.message || '服务未响应')breakcase 503:$vm.$toast.error(error.message || '服务暂不可访问')breakdefault:$vm.$toast.error(error.response.statusText || '服务异常, 请稍后重试')}} else {$vm.$toast.error(error.response.statusText || '未知错误, 请稍后重试')}reject(error)})
4.5 取消请求
在一些特定情况下,比如用户快速点击提交表单,短时间内同时触发同一个请求多次,我们可以借助 axios.cancelToken 来取消前几次请求,只保留最后一次请求。
主要实现的原理如下:
- 每次调用 request 函数时,根据传入的 method + api + JSON.stringify(config) 作为当前请求的标识 key,如果配置了
config.cancelTokenWidthParams = true
,时,在 key 后面拼接 JSON.stringify(params) 作为 key。 - HTTP_CANCEL_MAP 每一项的 key 为每个请求的 ‘唯一标识 + _ + 时间戳’,每一项 value 设置为 axios.CancelToken 构造函数传入的 executor 函数的参数,也就是 cancel 函数,调用 checkHttpCancel 函数传入 key 判断是否为重复请求,是重复请求则调用 cancel() 取消请求。
- 调用 request 函数时,配置 opts.cancelToken,使用 new 调用 CancelToken 的构造函数来创建 cancel token
- 请求响应成功和失败时都需要从 HTTP_CANCEL_MAP 中删除 reqUniqueKey 对应的 cancelToken
const CANCEL_TOKEN = axios.CancelToken
const HTTP_CANCEL_MAP = $globals.httpCancelMap = new Map()
const IS_CANCELED_MSG = 'canceled'const checkHttpCancel = reqKey => {HTTP_CANCEL_MAP.forEach((v, k) => {if (k.slice(0, -14) === reqKey) {v()HTTP_CANCEL_MAP.delete(k)}})
}const request = async (method = 'post', api, params = {}, config = {}) => {let reqKey = method + api + JSON.stringify(config)if (config.cancelTokenWidthParams) reqKey += JSON.stringify(params)let reqUniqueKey = reqKey + '_' + new Date().getTime()checkHttpCancel(reqKey)// 省略...opts.cancelToken = new CANCEL_TOKEN(c => HTTP_CANCEL_MAP.set(reqUniqueKey, c))// ...axios(opts).then(response => {HTTP_CANCEL_MAP.delete(reqUniqueKey)// ...}, error => {HTTP_CANCEL_MAP.delete(reqUniqueKey)if (axios.isCancel(error)) {reject(new Error(IS_CANCELED_MSG))return}// ...})
})
注意
- 此项目使用的 axios 版本为 0.21.1,从 v0.22.0 开始,Axios 支持以 fetch API 方式—— AbortController 取消请求,CancelToken API被弃用
- 可以使用同一个 cancel token 取消多个请求
三、完整的 http.js
import axios from 'axios'
import { TOKEN_REQ_KEY, TOKEN_COOKIE_KEY } from '@/const/common'
import { session, cookie, jsonObj2FormData } from '@/util/common'axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8'
axios.defaults.timeout = 120000
axios.defaults.crossDomain = trueaxios.interceptors.request.use(config => {const token = cookie.get(TOKEN_COOKIE_KEY)if (token) {config.headers[TOKEN_REQ_KEY] = token}return config},error => {return Promise.reject(error)}
)axios.interceptors.response.use(response => {return response
}, error => {return Promise.reject(error)
})const CANCEL_TOKEN = axios.CancelToken
const HTTP_CANCEL_MAP = $globals.httpCancelMap = new Map()
const IS_CANCELED_MSG = 'canceled'const checkHttpCancel = reqKey => {HTTP_CANCEL_MAP.forEach((v, k) => {if (k.slice(0, -14) === reqKey) {v()HTTP_CANCEL_MAP.delete(k)}})
}const apiInterceptor = api => {if (api.startsWith('http')) { // 自定义请求路径return api.slice(4)}if (api.startsWith('_SC_')) { // 项目统一的api前缀api = $globals.vipAddress + api.slice(4)}return $globals.httpBaseURL + api
}const request = async (method = 'post', api, params = {}, config = {}) => {let reqKey = method + api + JSON.stringify(config)if (config.cancelTokenWidthParams) reqKey += JSON.stringify(params)let reqUniqueKey = reqKey + '_' + new Date().getTime()checkHttpCancel(reqKey)return new Promise((resolve, reject) => {if (config.loading) $vm.$loading.show()let url = apiInterceptor(api)let opts = {method,url,headers: config.headers || {},withCredentials: config.withCredentials || true // 跨域请求时是否需要使用凭证}if (config.formDataFormat) {opts.headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'params = jsonObj2FormData(params)}if (config.timeout) opts.timeout = config.timeoutif (config.extends) opts = Object.assign(opts, config.extends) // 如果有并列层级的参数扩展if (method == 'post') {opts.data = params} else {opts.params = params}opts.cancelToken = new CANCEL_TOKEN(c => HTTP_CANCEL_MAP.set(reqUniqueKey, c))if (config.responseType) opts.responseType = config.responseType// 发起 axios 请求axios(opts).then(response => {HTTP_CANCEL_MAP.delete(reqUniqueKey)if (config.loading) $vm.$loading.close()let res = response.dataif (config.customHandler) { // 自定义响应处理if (config.responseAll) return resolve(response)return resolve(res)}if (res) {if (res.code === 000) { // 登录超时$vm.$toast.error(res.message)$vm.$store.dispatch('REMOVE_USER') // 移除 cookie、session、storage 存储的信息reject(res.message)if (window.self === window.top) {$vm.$router.push('/login') // 跳转登录页}} else if (res.code === 200) {resolve(res.data)} else {$vm.$toast.error(res.message || '接口异常, 请稍后重试')reject(res)}} else {$vm.$toast.error('接口无返回内容')}}, error => {HTTP_CANCEL_MAP.delete(reqUniqueKey)if (axios.isCancel(error)) {reject(new Error(IS_CANCELED_MSG))return}if (config.loading) $vm.$loading.close()// 如果自定义处理if (config.customHandler) {reject(error)return}// 请求超时if (error.code == 'ECONNABORTED' && error.message.indexOf('timeout') > -1) {$vm.$toast.error(`请求超时,接口地址:${url}`)reject(error)return}if (error.response) {// 401未登录或登录失效if (error.response.status === 401) {reject(error)if (window.self === window.top) {$vm.$router.push('/login')}return}switch (error.response.status) {case 404:$vm.$toast.error(`请求的资源不存在,异常服务接口地址:${url}`)breakcase 408:$vm.$toast.error('请求超时')breakcase 413:$vm.$toast.error('请求实体大小超过服务器最大限制')breakcase 500:$vm.$toast.error('服务异常')breakcase 502:$vm.$toast.error(error.message || '服务未响应')breakcase 503:$vm.$toast.error(error.message || '服务暂不可访问')breakdefault:$vm.$toast.error(error.response.statusText || '服务异常, 请稍后重试')}} else {$vm.$toast.error(error.response.statusText || '未知错误, 请稍后重试')}reject(error)})})
}export default {get: (api, params = {}, config = {}) => {return request('get', api, params, config)},post: (api, params = {}, config = {}) => {return request('post', api, params, config)},image: id => {return `${$globals.fileUrl}?fileId=${id}`},isCanceled: error => {if (error && error.message === IS_CANCELED_MSG) return truereturn false}
}
- http.image 方法仅用于返回文件的请求完整 url,使用场景为比如 <img> 标签中的 src 的值
- http.isCanceled 方法用于判断当前请求是否取消,如果有请求未取消并且出现全局 loading 加载未关闭的情况,可根据此标志来判断是否关闭
四、封装成插件并挂载到原型
/plugins/http/install.js
import httpService from '@/service/http'export default {install: Vue => {Vue.prototype.$http = httpService}
}
五、管理 api
例如,根据业务可划分为文档,评论等模块,在 service 目录下分别创建对应的模块存放 api 的 js 文件,对 api 进行统一管理。
强烈建议给每个 api 备注功能,提高可维护性
/service/comment.js
/*** @name 获取评论列表* @param {Object} params 请求参数对象*/
export const getCommentListPromise = params => {params = Object.assign({page: 0, // 页码pageSize: 5, // 每页数量}, params)return $vm.$http.get('_SC_/comment/findCommentList', params)
}
在 Comment.vue 页面中使用
import { getCommentListPromise } from '@/service/comment'
async findCommentList() {const data = await getCommentListPromise()console.log(data)
}
总结
本文主要讲述了如何使用 axios 进行 http 封装的详细过程,及在项目中如何使用封装的 http 请求,请求拦截器和响应拦截器都是比较简单,没有处理很多的逻辑,逻辑处理基本是集中在 request 函数中。
相关文章:

axios 封装 http 请求详解
前言 Axios 是一个基于 Promise 的 HTTP 库,它的概念及使用方法本文不过多赘述,请参考:axios传送门 本文重点讲述下在项目中是如何利用 axios 封装 http 请求。 一、预设全局变量 在 /const/preset.js 中配置预先设置一些全局变量 window.…...

牛客2024年愚人节比赛(A-K)
比赛链接 毕竟是娱乐场,放平心态打吧。。。 只有A一个考了数学期望,其他的基本都是acmer特有的脑筋急转弯,看个乐呵即可。 A 我是欧皇,赚到盆满钵满! 思路: 我们有 p 1 p_1 p1 的概率直接拿到一件实…...

loadbalancer 引入与使用
在消费中pom中引入 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> 请求调用加 LoadBalanced 注解 进行服务调用 默认负载均衡是轮训模式 想要切换…...
Yolov5封装detect.py面向对象
主要目标是适应摄像头rtsp流的检测 如果是普通文件夹或者图片,run中的while True去掉即可。 web_client是根据需求创建的客户端,将检测到的数据打包发送给服务器 # YOLOv5 🚀 by Ultralytics, GPL-3.0 license """ Run inf…...

入门级深度学习主机组装过程
一 配置 先附上电脑配置图,如下: 利用公司的办公电脑对配置进行升级改造完成。除了显卡和电源,其他硬件都是公司电脑原装。 二 显卡 有钱直接上 RTX4090,也不能复用公司的电脑,其他配置跟不上。 进行深度学习&…...

python爬虫之selenium4使用(万字讲解)
文章目录 一、前言二、selenium的介绍1、优点:2、缺点: 三、selenium环境搭建1、安装python模块2、selenium4新特性3、安装驱动WebDriver驱动选择驱动安装和测试 基础操作1、属性和方法2、单个元素定位通过id定位通过class_name定位一个元素通过xpath定位…...
【ARM 嵌入式 C 头文件系列 22 -- 头文件 stdint.h 介绍】
请阅读【嵌入式开发学习必备专栏 】 文章目录 C 头文件 stdint.h定长整数类型最小宽度整数类型最快最小宽度整数类型整数指针类型最大整数类型 C 头文件 stdint.h 在 C 语言中,头文件 <stdint.h> 是 C99 标准的一部分,旨在提供一组明确的整数类型…...

LabVIEW专栏三、探针和断点
探针和断点是LabVIEW调试的常用手段,该节以上一节的"测试耗时"为例 探针可以打在有线条的任何地方,打上后,经过这条线的所有最后一次的数值都会显示在探针窗口。断点可以打在程序框图的所有G代码对象,包括结构…...

Transformer模型-softmax的简明介绍
今天介绍transformer模型的softmax softmax的定义和目的: softmax:常用于神经网络的输出层,以将原始的输出值转化为概率分布,从而使得每个类别的概率值在0到1之间,并且所有类别的概率之和为1。这使得Softmax函数特别适…...
记录一下做工厂的打印pdf程序
功能:在网页点击按钮调起本地的打印程序 本人想到的就是直接调起方式,网上大佬们说用注册表的形式来进行。 后面想到一种,在电脑开机时就开启,并在后台运行,等到有人去网页里面进行触发,这时候就有个问题&a…...

Linux网络编程一(协议、TCP协议、UDP、socket编程、TCP服务器端及客户端)
文章目录 协议1、分层模型结构2、网络应用程序设计模式3、ARP协议4、IP协议5、UDP协议6、TCP协议 Socket编程1、网络套接字(socket)2、网络字节序3、IP地址转换4、一系列函数5、TCP通信流程分析 第二次更新,自己再重新梳理一遍… 协议 协议:指一组规则&…...

Python读取Excel根据每行信息生成一个PDF——并自定义添加文本,可用于制作准考证
文章目录 有点小bug的:最终代码(无换行):有换行最终代码无bug根据Excel自动生成PDF,目录结构如上 有点小bug的: # coding=utf-8 import pandas as pd from reportlab.pdfgen import canvas from reportlab.lib.pagesizes import letter from reportlab.pdfbase import pdf…...

http: server gave HTTP response to HTTPS client 分析一下这个问题如何解决中文告诉我详细的解决方案
这个错误信息表明 Docker 客户端在尝试通过 HTTPS 协议连接到 Docker 仓库时,但是服务器却返回了一个 HTTP 响应。这通常意味着 Docker 仓库没有正确配置为使用 HTTPS,或者客户端没有正确配置以信任仓库的 SSL 证书。以下是几种可能的解决方案࿱…...

Flume学习笔记
视频地址:https://www.bilibili.com/video/BV1wf4y1G7EQ/ 定义 Flume是一个高可用的、高可靠的、分布式的海量日志采集、聚合和传输的系统。 Flume高最要的作用就是实时读取服务器本地磁盘的数据,将数据写入HDFS。 官网:https://flume.apache.org/releases/content/1.9.0/…...

数据库系统概论(超详解!!!) 第三节 关系数据库标准语言SQL(Ⅳ)
1.集合查询 集合操作的种类 并操作UNION 交操作INTERSECT 差操作EXCEPT 参加集合操作的各查询结果的列数必须相同;对应项的数据类型也必须相同 查询计算机科学系的学生及年龄不大于19岁的学生。SELECT *FROM StudentWHERE Sdept CSUNIONSELECT *FROM StudentWHERE Sage&l…...

与谷歌“分家”两年后,SandboxAQ推出统一加密管理平台
3月27日,SandboxAQ宣布其AQtive Guard平台现已全面可用(GA),适用于所有行业,以防范人工智能驱动和量子攻击的威胁。前者是在两年前3月从谷歌母公司Alphabet分拆出来的初创公司,并在当时获得了“九位数”的融…...

【卫星家族】 | 高分六号卫星影像及获取
1. 卫星简介 高分六号卫星(GF-6)于2018年6月2日在酒泉卫星发射中心成功发射,是高分专项中的一颗低轨光学遥感卫星,也是我国首颗精准农业观测的高分卫星,具有高分辨率、宽覆盖、高质量成像、高效能成像、国产化率高等特…...
XML与Xpath
XML与Xpath XML是一种具有某种层次结构的文件,Xpath则是解析这种文件的工具 接下来将会解释XML文件的结构和Xpath的基本使用,并且用Java语言进行操作展示。 XML结构 XML(可扩展标记语言)文件具有一种层次结构,由标签…...
【c++20】CPP-20-STL-Cookbook 学习笔记
Cpp20-STL-Cookbook-src简单的阅读笔记。c++20更好用了,比如STL 包含了一些这样的辅助函数,比如 make_pair() 和make_tuple() 等。 这些代码现在已经过时了,但是为了与旧代码兼容,会保留这些代码。比如 可以声明是一个std的string:Sum s1 {1u, 2.0, 3, 4.0f }?...

Python 之 Flask 框架学习
毕业那会使用过这个轻量级的框架,最近再来回看一下,依赖相关的就不多说了,直接从例子开始。下面示例中的 html 模板,千万记得要放到 templates 目录下。 Flask基础示例 hello world from flask import Flask, jsonify, url_fora…...

边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...

html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...

Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...
规则与人性的天平——由高考迟到事件引发的思考
当那位身着校服的考生在考场关闭1分钟后狂奔而至,他涨红的脸上写满绝望。铁门内秒针划过的弧度,成为改变人生的残酷抛物线。家长声嘶力竭的哀求与考务人员机械的"这是规定",构成当代中国教育最尖锐的隐喻。 一、刚性规则的必要性 …...
【深尚想】TPS54618CQRTERQ1汽车级同步降压转换器电源芯片全面解析
1. 元器件定义与技术特点 TPS54618CQRTERQ1 是德州仪器(TI)推出的一款 汽车级同步降压转换器(DC-DC开关稳压器),属于高性能电源管理芯片。核心特性包括: 输入电压范围:2.95V–6V,输…...

Python异步编程:深入理解协程的原理与实践指南
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 持续学习,不断…...

篇章一 论坛系统——前置知识
目录 1.软件开发 1.1 软件的生命周期 1.2 面向对象 1.3 CS、BS架构 1.CS架构编辑 2.BS架构 1.4 软件需求 1.需求分类 2.需求获取 1.5 需求分析 1. 工作内容 1.6 面向对象分析 1.OOA的任务 2.统一建模语言UML 3. 用例模型 3.1 用例图的元素 3.2 建立用例模型 …...