文件上传总结:用原生解决前端文件上传操作(单个,多个,大文件切片)

目录

第一章 前言

第二章 理解文件上传的对象

2.1 如何利用原生实现

2.2 认识理解文件上传的四个对象

2.2.1 file对象

2.2.2 blob对象

2.2.3  formData对象

2.2.4 fileReader对象 

2.2.4.1 了解fileReader对象基本属性

2.2.4.2 了解 fileReader对象基本方法

2.2.4.3  了解fileReader对象基本事件

第三章 理解四个对象的使用

3.1 file与blob对象的使用

3.1.1 file对象转blob对象

3.1.2 blob对象转file对象

3.2 formData的使用

第四章 实战应用

4.1 单文件上传

4.2 多文件上传

4.3 切片上传

4.3.1 如何处理多个图片

4.3.2 实现切片上传 

第五章 源码


第一章 前言

相信我们很多人在项目中都会实现图片上传这么个功能,并且也会使用FormData和elementUI、antd等框架的upload组件实现,但是一延伸到原理、细节时就很难受,说不出所以然(小编也体验过,哈哈哈哈),所以如下是小编最近总结的点。

  • 用到的前端页面
    <input type="file" @change="fileChange" multiple /><button @click="submit">多选提交</button><span v-for="(item, index) in fileList" :key="index">{{ item.name }}</span><button @click="dealFile">处理图片信息</button>

第二章 理解文件上传的对象

2.1 如何利用原生实现

  • 利用input原生标签,type为file形式,multiple为多选,accept可以限制上传的文件类型,@change是使用的方法

<input type="file" @change="fileChange" multiple />

HTML input 标签 | 菜鸟教程

  • 我们可以看到最终返回的数据类型是File对象 

一个或多个文件对象组成的数组

 

2.2 认识理解文件上传的四个对象

2.2.1 file对象

  • 通过指定input标签type属性为file来读取files对象,是一个由一个或多个文件对象组成的数组

2.2.2 blob对象

  • 表示二进制类型的大对象。在数据库管理系统中,将二进制数据存储为一个单一个体的集合。Blob 通常是影像、声音或多媒体文件。在 JavaScript 中 Blob 类型的对象表示不可变的类似文件对象的原始数据, 使用构造函数创建。

2.2.3  formData对象

  • 利用它来提交表单、模拟表单提交,最大的优势就是可以上传二进制文件
  • 熟悉formData:

 前后端传参:掌握FormData并解决form-data类型传参问题_前端formdata传参-CSDN博客

2.2.4 fileReader对象 

  • 构造函数方式实例化一个fileReader对象,readAs()方法将文件对象读取成base64格式或者文本格式
2.2.4.1 了解fileReader对象基本属性
  • 直接使用时
const reader = new FileReader()
console.log('FileReader方法及属性:', reader)
  • 查看方法及属性:

 

  • FileReader.error(只读属性):读取文件时报的错误,null表示在读取用户所上传文件时没有出错
  • FileReader.readyState(只读属性):加载状态
状态值描述
0还没有加载任何数据
1数据正在被加载
2已完成全部的读取请求
  • FileReader.result(只读属性):表示文件的内容,仅在读取操作完成之后才有效,数据的格式取决于使用哪个方法(在2.2.4.2中)来启动读取操作
const reader = new FileReader()
console.log('FileReader方法及属性:', reader)
console.log('尝试使用只读属性error:', reader.error)
console.log('尝试使用只读属性readyState:', reader.readyState)
console.log('尝试使用只读属性result:', reader.result)

2.2.4.2 了解 fileReader对象基本方法
  •  我们顺着原型链往下找可以发现,该对象下还有以下四种方法

方法描述
FileReader.abort()终止读取操作
FileReader.readAsArrayBuffer()开始读取指定文件中的内容,一旦完成,result属性中保存的是被读取文件的ArrayBuffer数据对象
FileReader.readAsBinaryString()开始读取指定文件中的内容,一旦完成,result属性中保存的是所读取文件的原始二进制数据
FileReader.readAsDataURL()开始读取指定文件中的内容,一旦完成,result属性中是一个data:URL格式的Base64字符串以表示所读取文件的内容
FileReader.readAsText()开始读取指定文件中的内容,一旦完成,result属性中保存的是一个字符串以表示所读取的文件内容
  • 理解 FileReader.abort()的使用
dealFile () {this.fileList.forEach(item => {const reader = new FileReader()reader.abort()console.log('走到这了1')reader.onload = (res) => {console.log('走到这了2')}})
},

 

由于 FileReader.abort() 终止了读取操作,所以不会执行onload执行完毕触发的函数中的代码

  • 理解 FileReader.readAsArrayBuffer()的使用
dealFile () {this.fileList.forEach(item => {const reader = new FileReader()reader.readAsArrayBuffer(item)reader.onload = (res) => {console.log('执行readAsArrayBuffer返回的数据', res)console.log('返回的result值为:', res.target.result)}})
},

  • 理解 FileReader.readAsBinaryString() 的使用
dealFile () {this.fileList.forEach(item => {const reader = new FileReader()reader.readAsBinaryString(item)reader.onload = (res) => {console.log('执行readAsBinaryString返回的数据', res)console.log('返回的result值为:', res.target.result)}})
},

注意:该信息是原始的二进制文件信息 

  •  理解 FileReader.readAsDataURL() 的使用
dealFile () {this.fileList.forEach(item => {const reader = new FileReader()reader.readAsDataURL(item)reader.onload = (res) => {console.log('执行readAsDataURL返回的数据', res)console.log('返回的result值为:', res.target.result)}})
},

  • 理解 FileReader.readAsText() 的使用
dealFile () {this.fileList.forEach(item => {const reader = new FileReader()reader.readAsText(item)reader.onload = (res) => {console.log('执行readAsText返回的数据', res)console.log('返回的result值为:', res.target.result)}})
},

 注意:小编这里识别的是txt文档中的文字,如果上传的是图片,会说乱码

2.2.4.3  了解fileReader对象基本事件
  • 查看回调事件

事件方法描述
FileReader.onabort()处理abort事件,该事件在读取操作被中断时触发
FileReader.onerror()处理error事件,该事件在读取操作发生错误时触发
FileReader.onload()处理load事件,该事件在读取操作完成时触发
FileReader.onloadstart()处理loadstart事件,该事件在读取操作开始时触发
FileReader.onloadend()处理loadend事件,该事件在读取操作结束时(成功或失败)触发
FileReader.onprogress()处理progress事件,该事件正在读取时触发
  •  使用方法:
dealFile () {this.fileList.forEach(item => {const reader = new FileReader()reader.onabort = (res) => {console.log('读取中断了onabort', res)}reader.onerror = (res) => {console.log('读取发生错误了onerror', res)}reader.onload = (res) => {console.log('读取完成了onload', res)}reader.onloadstart = (res) => {console.log('读取开始了onloadstart', res)}reader.onloadend = (res) => {console.log('读取结束了onloadend', res)}reader.onprogress = (res) => {console.log('读取进行中onprogress', res)}})
},
  •  输出结果

  • 由上可知执行顺序为

 1、onloadstart -> onprogress -> onload  -> onloadend 

2、当使用 reader.abort() 方法中断读取时会执行onabort 

3、当读取错误时会执行onerror

第三章 理解四个对象的使用

3.1 file与blob对象的使用

3.1.1 file对象转blob对象

fileToBlob (file) {// new Blob([文件二进制流], 文件类型)const blob = new Blob([file], { type: file.type }) // 直接利用Blob的方法console.log('blob', blob)return blob
},

3.1.2 blob对象转file对象

// blob二进制流转file二进制流注意要再携带参数文件名
blobToFile (blob, fileName) {// new File([blob二进制流], 文件名, 文件类型)const file = new File([blob], fileName, { type: blob.type })console.log('file', file)
},

3.2 formData的使用

前后端传参:掌握FormData并解决form-data类型传参问题_前端formdata传参-CSDN博客

第四章 实战应用

4.1 单文件上传

  • 利用input元素的accept属性限制上传文件的类型,multiple限制能否多选
  •  完整代码:

        -- html部分——

<template><div><input type="file" @change="fileChange"/>// 该按钮支持单个文件上传与多个文件上传<button @click="submit">多选提交</button><span v-for="(item, index) in fileList" :key="index">{{ item.name }}</span></div>
</template>

         -- js部分——

<script>
import axios from 'axios'
export default {data () {return {fileList: [] // 定义空数组存储多个文件}},components: {},methods: {fileChange (e) {// 一个由不同文件对象组成的对象console.log('文件对象e,文件方法:e.target.files', e, e.target.files)// 单文件上传this.fileList = []this.fileList.push(e.target.files[0])},async submit () {const _formdata = new FormData()// 循环fileList,每次都创建一个formdata对象上传this.fileList.forEach(async item => {// 转二进制流形式上传const blob = new Blob([item], { type: item.type })console.log('blob', blob)_formdata.append('files', blob, item.name)})axios({url: '/api/upload',method: 'POST',headers: {'Content-type': 'multipart/form-data'},data: _formdata}).then(response => {console.log(response)}).catch(err => {console.log(err)})}}
}

        -- 页面展示:

  • 上传成功(只选择一个文件上传即可)

  •  传参

4.2 多文件上传

  • 将多个文件放到一个数组内,然后循环这个数组内的文件对象,利用formdata实现;可以每处理一次,然后调用一次接口,上传一个文件;也可以将数组中的文件对象都处理好之后,调用接口上传所有文件

  • 注意:该接口的实现需要与后端商量好可以如何上传

  • html部分——
<template><div>// 支持批量上传<input type="file" @change="fileChange" multiple />// 该按钮支持单个文件上传与多个文件上传<button @click="submit">多选提交</button><span v-for="(item, index) in fileList" :key="index">{{ item.name }}</span></div>
</template>
  • 方法一:遍历数组中的文件对象,利用formdata处理值,每处理一次,调用一次方法
<script>
import axios from 'axios'
export default {data () {return {fileList: [] // 定义空数组存储多个文件}},components: {},methods: {fileChange (e) {// 一个由不同文件对象组成的对象console.log('文件对象e,文件方法:e.target.files', e, e.target.files)// 检测e.target.files是否有多个文件if (e.target.files.length > 1) {// 如果上传了多个文件将其合并this.fileList = [...this.fileList, ...e.target.files]// this.fileList = this.fileList.concat(e.target.files)} else {this.fileList.push(e.target.files[0])}},async submit () {// 循环fileList,每次都创建一个formdata对象上传this.fileList.forEach(async item => {const _formdata = new FormData()const blob = new Blob([item], { type: item.type })console.log('blob', blob)_formdata.append('files', blob, item.name)axios({url: '/api/upload',method: 'POST',headers: {'Content-type': 'multipart/form-data'},data: _formdata}).then(response => {console.log(response)}).catch(err => {console.log(err)})})}}
}

 

  •  方法二:遍历数组中的文件对象,利用formdata处理值,利用formdata.append将每一次处理的值添加到formdata对象中,最后上传所有文件
<script>
import axios from 'axios'
export default {data () {return {fileList: [] // 定义空数组存储多个文件}},components: {},methods: {fileChange (e) {// 一个由不同文件对象组成的对象console.log('文件对象e,文件方法:e.target.files', e, e.target.files)// 检测e.target.files是否有多个文件if (e.target.files.length > 1) {// 如果上传了多个文件将其合并this.fileList = [...this.fileList, ...e.target.files]// this.fileList = this.fileList.concat(e.target.files)} else {this.fileList.push(e.target.files[0])}},async submit () {const _formdata = new FormData()// 循环fileList,每次都创建一个formdata对象上传this.fileList.forEach(async item => {// 转二进制流形式上传const blob = new Blob([item], { type: item.type })console.log('blob', blob)_formdata.append('files', blob, item.name)})axios({url: '/api/upload',method: 'POST',headers: {'Content-type': 'multipart/form-data'},data: _formdata}).then(response => {console.log(response)}).catch(err => {console.log(err)})}}
}

 

  • 多文件上传两种方法可能会涉及到的问题:
  1. 当上传数量过多时(上百上千时),处理一条数据发一个请求,造成频繁的调用接口,对服务器会有一定的影响;用户频繁上传大量的图片,服务器需要处理和存储这些图片,会消耗大量的带宽和存储空间,这可能导致服务器负载增加,影响了服务器的性能表现。此外,图片上传过程中的网络传输也会占用服务器的网络资源,对其他用户的访问速度可能会有所影响。
  2. 但时当一次性上传或者打包上传特别大的文件时,又有可能出现上传文件过大,后端处理文件的时间太长,但是前端设置的响应时间没有这么长,到了时间之后前端就会报错,那么这上传又如何处理

4.3就是如何解决上述两个问题中的方法之一:分片上传

4.3 切片上传

4.3.1 如何处理多个图片

  • 当用户上传大量图片时,如果我们使用4.2中了两种方法会出现的问题已经了解了,那么我们如何解决呢,如何处理这批量的图片呢?
  • 小编给出如下方法:

input标签设置multiple上传大量文件 -> 上传时将每一个文件的二进制流封装成一个promise对象 ->每一个promise对象push到一个数组 -> 利用promise.all确定数组中promise的状态值都是成功状态,promise.all为成功态才会执行代码 -> 遍历promise数组获取里面的二进制流文件 -> 利用jszip组件将所有的文件打包成压缩包的二进制流 -> (前端可以利用file-saver下载查看压缩包内容) -> 最后将改压缩包的二进制流进行分片上传

  • 处理多个图片的代码:

html部分——

<template><div><input type="file" @change="fileChange" multiple/><button @click="imageCompress">压缩图片</button><span v-for="(item, index) in fileList" :key="index">{{ item.name }}</span></div>
</template>

js部分——

<script>
import axios from 'axios'
import JSZip from 'jszip'
// import FileSaver from 'file-saver'export default {data () {return {fileList: [], // 定义空数组存储多个文件filesPromises: [] // 存放二进制文件流的promise数组}},components: {},methods: {// 利用promise处理多个图片// 将每一个文件的二进制流封装成一个promise对象dealFiles (file) {return new Promise((resolve, reject) => {resolve({ file })})},// 图片压缩imageCompress () {// 利用promise.allPromise.all(this.filesPromises).then(async (files) => {// 定义一个JSZip实例const zip = new JSZip()// 遍历数据 遍历promise数组获取里面的二进制流文件files.forEach(async (item, index) => {const { file } = itemconsole.log('每一个二进制流文件数据为:', file)// 添加需要压缩的文件,二进制流的形式await zip.file(file.name, file)})// 下载压缩包zip.generateAsync({ type: 'blob' }).then((content) => {console.log('压缩包的二进制流信息', content)// 下载上面压缩的压缩包FileSaver.saveAs(content, '合并的内容' + '.zip')})}).catch(err => {console.log(err)})},fileChange (e) {// 一个由不同文件对象组成的对象console.log('文件对象e,文件方法:e.target.files', e, e.target.files)// 检测e.target.files是否有多个文件if (e.target.files.length > 1) {this.fileList = [...this.fileList, ...e.target.files]// this.fileList = this.fileList.concat(e.target.files)} else {this.fileList.push(e.target.files[0])}// 处理文件信息成promise对象// 每一个promise对象push到一个数组this.fileList.forEach(item => {this.filesPromises.push(this.dealFiles(item))})console.log('存放文件的列表', this.fileList, this.filesPromises)}}
}
</script>

 页面效果——

上传多个文件:

将每一个promise对象push到一个数组中 :

查看处理后的数据信息:

利用file-saver插件中的方法下载的内容: 

 

成功利用jszip插件中的方法将上传的图片打压成压缩包: 

 

4.3.2 实现切片上传 

  •  切片上传的核心就是利用二进制流中的size(文件大小)的slice方法切割数据流,将每一段二进制流数据发送请求给后端,当发送完成后,由后端合并,最终返回前端想要的数据

 html部分——

<template><div><input type="file" @change="fileChange" multiple/><button @click="shardingSubmit">分片提交</button><button @click="imageCompress">压缩图片</button><span v-for="(item, index) in fileList" :key="index">{{ item.name }}</span><div>上传进度:{{ precent }}%</div></div>
</template>

js部分—— (先点击压缩图片按钮,再点击分片提交)

注意:一定要与后端沟通好传参的格式

<script>
import axios from 'axios'
import JSZip from 'jszip'
// import FileSaver from 'file-saver'export default {data () {return {fileList: [], // 定义空数组存储多个文件filesPromises: [], // 存放二进制文件流的promise数组compreeContent: null}},components: {},methods: {// 分片上传async shardingSubmit () {const size = 1024 * 1024// 注意 ======== 从这开始时小编传一个文件做的切片上传测试// const fileData = this.fileList[0]// console.log('fileData', fileData)// // const fileName = fileData.name.split('.')[0]// const blob = new Blob([fileData], { type: fileData.type })// 注意 ======== 到这结束,获取blob二进制数据流的过程const blob = this.compreeContentconst blobSize = blob.sizelet current, iconsole.log('blob', blob, blob.size)for (current = 0, i = 0; current < blobSize; current += size, i++) {const _formdata = new FormData()// 一次添加1M大小的切片  注意添加时的说明一般为文件名,后端接收后按照文件名标识拼接// 传参格式(与后端沟通好)_formdata.append('file', blob.slice(current, current + size))_formdata.append('chunkIndex', i + 1)_formdata.append('chunkTotal', Math.ceil(blobSize / size))_formdata.append('name', `片段${Math.ceil(blobSize / size)}`)// 这里可以通过传参动态解决_formdata.append('suffix', 'zip')// _formdata.append('suffix', 'png')axios({url: '/api/part',method: 'POST',headers: {'Content-type': 'multipart/form-data'},data: _formdata}).then(response => {console.log(response)// 计算当前上传进度,展示到页面// 小编只是实现了分片上传的逻辑,进度条未处理好this.precent = Math.ceil(((current) / blobSize) * 100)}).catch(err => {console.log(err)})}},// 利用promise处理多个图片// 将每一个文件的二进制流封装成一个promise对象dealFiles (file) {return new Promise((resolve, reject) => {resolve({ file })})},// 图片压缩/文件imageCompress () {// 利用promise.allPromise.all(this.filesPromises).then(async (files) => {// 定义一个JSZip实例const zip = new JSZip()// 遍历数据 遍历promise数组获取里面的二进制流文件files.forEach(async (item, index) => {const { file } = itemconsole.log('每一个二进制流文件数据为:', file)// 添加需要压缩的文件,二进制流的形式await zip.file(file.name, file)})// 下载压缩包zip.generateAsync({ type: 'blob' }).then((content) => {console.log('压缩包的二进制流信息', content)this.compreeContent = content// 下载上面压缩的压缩包// FileSaver.saveAs(content, '合并的内容' + '.zip')})}).catch(err => {console.log(err)})},fileChange (e) {// 一个由不同文件对象组成的对象console.log('文件对象e,文件方法:e.target.files', e, e.target.files)// 检测e.target.files是否有多个文件if (e.target.files.length > 1) {this.fileList = [...this.fileList, ...e.target.files]// this.fileList = this.fileList.concat(e.target.files)} else {this.fileList.push(e.target.files[0])}// 处理文件信息成promise对象// 每一个promise对象push到一个数组this.fileList.forEach(item => {this.filesPromises.push(this.dealFiles(item))})console.log('存放文件的列表', this.fileList, this.filesPromises)}}
}
</script>

 后端合并结果:(这里只是demo,具体情况具体解析)

第五章 源码

batch_file_upload: 文件上传(单个、多个、分片)代码

参数说明:

  • 单个/多个上传

  • 分片上传

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

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

相关文章

【高阶数据结构】位图布隆过滤器

文章目录 1. 位图1.1什么是位图1.2为什么会有位图1.3 实现位图1.4 位图的应用 2. 布隆过滤器2.1 什么是布隆过滤器2.2 为什么会有布隆过滤器2.3 布隆过滤器的插入2.4 布隆过滤器的查找2.5 布隆过滤器的模拟实现2.6 布隆过滤器的优点2.7 布隆过滤器缺陷 3. 海量数据面试题3.1 哈…

mysql 对于null字段排序处理

最近遇到一个需求 &#xff0c;需要对一个报表的多个字段进行多字段复杂条件排序 排序字段为NULL时 Mysql对于排序字段为NULL时&#xff0c;有自身默认的排序规则&#xff0c;默认是认为null 值 是无穷小 ELECT id,script_id,last_modified,live_count,next_show FROM virtua…

Kubernetes 简介

&#x1f4ce;k8s 入门到微服务项目实战.xmindhttps://www.yuque.com/attachments/yuque/0/2024/xmind/35457682/1707117691869-1ea2805d-7218-4223-a0a9-877147ca84b2.xmind 目录 1、概念介绍 应用部署的演变 Kubernetes 架构图 分层架构 2、Kubernetes 组件 控制面板组…

@PostMapping/ @GetMapping等请求格式

目录 1.只传一个参数的 第一种 第二种 第三种:表单 2.传整个对象的 2.1修改实体类就是传整个对象过来 2.2新增实体类就是传整个对象过来新增 1.只传一个参数的 第一种 PostMapping("/add/{newsId}")public Result addOne(PathVariable Integer newsId) {}pos…

【GAMES101】Lecture 19 透镜

目录 理想的薄透镜 模糊 利用透镜模型做光线追踪 景深&#xff08;Depth of Field&#xff09; 理想的薄透镜 在实际的相机中都是用的一组透镜来作为这个镜头 这个因为真实的棱镜无法将光线真正聚焦到一个点上&#xff0c;它只能聚在一堆上 所以方便研究提出了一种理想化的…

vue3 解决ionic安卓版顶部状态栏空白问题

问题展示&#xff1a; 解决&#xff1a;引入capacitor/status-bar npm install capacitor/status-bar npx cap sync在需要设置状态栏的组件上设置背景跟颜色即可

spring boot整合 cache 以redis服务 处理数据缓存 便捷开发

我们常规开发中 就是程序去数据库取数据 然后返回给客户端 但是 如果有些业务业务量非常庞大 不断访问数据库 性能就会非常糟糕 从而造成不好的用户体验 那么 我们自然就可以将数据查到缓存中 然后 用户访问 从缓存中取 这样就会大大提高用户的访问效率 之前 我的文章 java …

vue3集成bpmn

文章目录 前言一、依赖二、汉化配置1.引入文件2.样式文件 总结 前言 vue3 集成bpmn 配置工作流 一、依赖 "bpmn-js": "^7.3.1", "bpmn-js-properties-panel": "^0.37.2", "bpmn-moddle": "^6.0.0", "camu…

C#,聚会数(相遇数,Rencontres Number)的算法与源代码

1 相遇数 相遇数&#xff08;Rencontres Number&#xff0c;partial derangement numbers&#xff09;是指部分扰动的数量&#xff0c;或与独立对象的r相遇的置换数&#xff08;即具有固定点的独立对象的置换数&#xff09;。 看不通。懂的朋友给解释一下哈。 2 源程序 using…

DC-8靶机渗透详细流程

信息收集&#xff1a; 1.存活扫描&#xff1a; arp-scan -I eth0 -l └─# arp-scan -I eth0 -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:dd:ee:6a, IPv4: 192.168.10.129 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.10…

版本控制工具——Git

版本控制工具——Git 前言一、版本库二、git的工作区域和文件状态三、添加和提交文件四、回退版本&#xff1a;git reset --模式 版本号五、查看差异&#xff1a;git diff六、从版本库中删除文件七、.gitignore&#xff1a;git中的特殊文件八、Git、GitHub跟Sourcetree的关系九…

python多线程连接MySQL查数案例

该博文展示地是基本示例&#xff0c;实际使用时可能需要进行调整。例如&#xff0c;你可能需要添加错误处理来确保数据库连接问题不会导致脚本崩溃&#xff0c;或者你可能需要调整查询以匹配你的数据。 此外&#xff0c;你需要确保你的系统有足够的内存和处理能力来支持并行处理…

【JS逆向一】逆向某站的 加密参数算法--仅供学习参考

逆向日期&#xff1a;2024.02.06 使用工具&#xff1a;Node.js 文章全程已做去敏处理&#xff01;&#xff01;&#xff01; 【需要做的可联系我】 可使用AES进行解密处理&#xff08;直接解密即可&#xff09;&#xff1a;在线AES加解密工具 1、打开某某网站(请使用文章开头的…

有道ai写作,突破免费限制,无限制使用

预览效果 文末提供源码包及apk下载地址有道ai写作python版 import hashlib import time import json import ssl import base64 import uuidfrom urllib.parse import quote import requests from requests_toolbelt.multipart.encoder import MultipartEncoder from Crypto.C…

SpringSecurity+OAuth2权限管理实战

Spring Security快速入门 官方文档&#xff1a; Spring Security :: Spring Security 功能&#xff1a; 身份认证&#xff08;authentication&#xff09; 授权&#xff08;authorization&#xff09; 防御常见攻击&#xff08;protection against common attacks&#xff…

Oracle篇—logminer日志挖掘恢复误操作数据

☘️博主介绍☘️&#xff1a; ✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ ✌✌️擅长Oracle、MySQL、SQLserver、Linux&#xff0c;也在积极的扩展IT方向的其他知识面✌✌️ ❣️❣️❣️大佬们都喜欢静静的看文章&#xff0c;并且也会默默的点赞收藏加关注❣…

YouTrack 用户登录提示 JIRA 错误

就算输入正确的用户名和密码&#xff0c;我们也得到了下面的错误信息&#xff1a; youtrack Cannot retrieve JIRA user profile details. 解决办法 出现这个问题是因为 YouTrack 在当前的系统重有 JIRA 的导入关联。 需要把这个导入关联取消掉。 找到后台配置的导入关联&a…

FPGA_简单工程_无源蜂鸣器驱动实验

一 理论 蜂鸣器按其结构可分为电磁式蜂鸣器和压电式蜂鸣器2中类型&#xff0c;按其有无信号源&#xff0c;分为有源蜂鸣器和无源蜂鸣器。 有源蜂鸣器&#xff0c;内部装有集成电路&#xff0c;不需要音频驱动电路&#xff0c;就直接能发出声响&#xff0c;而无源蜂鸣器&#…

AWS配置内网EC2服务器上网【图形化配置】

第一种方法&#xff1a;创建EC2选择启用分配公网ip 1. 创建vpc 2. 创建子网 3. 创建互联网网关 创建互联网网关 创建互联网网关 &#xff0c;设置名称即可 然后给网关附加到新建的vpc即可 4. 给新建子网添加路由规则&#xff0c;添加新建的互联网网关然后点击保存更改 5. 新建…

HTTP协议笔记

HTTP协议笔记 参考&#xff1a; &#xff08;建议精读&#xff09;HTTP灵魂之问&#xff0c;巩固你的 HTTP 知识体系 《透视 HTTP 协议》——chrono 目录&#xff1a; 1、说说你对HTTP的了解吧。  1. HTTP状态码。  2. HTTP请求头和响应头&#xff0c;其中包括cookie、跨域响…