前端的几种网络请求方式

网络请求

node编写接口

这里用到的几个包的作用

  • express:基于 Node.js 平台,快速、开放、极简的 Web 开发框架,官网:https://www.expressjs.com.cn/
  • cors:用来解决跨域问题
  • body-parser:可以通过 req.body 获取post请求传递过来的json数据
  • multer:用于文件上传
const express = require('express');
const fs = require("fs");
const path = require("path")
const app = express()
const multer = require("multer");
const cors = require("cors")
const bodyParser = require("body-parser")
app.use(cors())
app.use(bodyParser.json())
// 设置上传目录和文件名
const storage = multer.diskStorage({destination: function (req, file, cb) {cb(null, 'uploads/')},filename: function (req, file, cb) {console.log(file)cb(null, Date.now() + path.extname(file.originalname))}
})const upload = multer({ storage: storage });app.get("/name",(req,res)=>{res.send({code:200,msg:"成功"})
})app.post("/add",(req,res)=>{console.log(req.body)// 使用req.body接收前端传递过来的post参数let data = req.bodyres.send({code:200,data:data})
})app.post("/upload", upload.single("file"), (req, res) => {if (!req.file) {return res.status(400).send('No file uploaded.');}// 输出文件信息console.log('Uploaded: ' + req.file.filename);res.send({code:200,data:'文件上传成功'})
});app.get("/sse", (req, res) => {// 声明链接方式是sseres.writeHead(200,{"Content-Type":"text/event-stream"})const text = fs.readFileSync("./read.txt","utf8")const arr = text.split("")let current = 0// 设置每隔20毫秒主动发送一次数据let timer = setInterval(()=>{if(current >= arr.length){clearInterval(timer)}else{// 发送消息必须是 data: 开头,\n\n 结尾。中间是发送的内容,内容必须是一个字符串res.write(`data:${arr[current]}\n\n`)current++}},20)
})app.listen(10086, () =>{console.log("启动成功: http://localhost:10086")
})

Ajax请求

发送GET请求

let xhr = new XMLHttpRequest()
function sendGet(){xhr.open("GET","http://127.0.0.1:10086/name")// 当接口相应数据后会触发onload回调xhr.onload = function (){if(xhr.status === 200){console.log(JSON.parse(xhr.responseText))}}xhr.send()
}

发送POST请求

let xhr = new XMLHttpRequest()
function sendPost(){xhr.open("POST","http://127.0.0.1:10086/add")xhr.setRequestHeader("Content-Type","application/json")xhr.onload = function (){if(xhr.status === 200){console.log(JSON.parse(xhr.responseText))}}// 定义发送给后端的数据let data = {name:"张三",age:18}// 把数据放在send中进行发送,需要使用JSON.stringify进行序列化xhr.send(JSON.stringify(data))
}

image-20231104170332434

上传文件

var fileEl = document.getElementById("file");
fileEl.addEventListener("change",event=>{let file = event.target.files[0]xhr.open("POST","http://127.0.0.1:10086/upload")xhr.onload = function (){if(xhr.status === 200){console.log(JSON.parse(xhr.responseText))}}let data = new FormData()data.append("file",file)xhr.send(data)
})

image-20231104172140646

image-20231104172206960

设置超时时间

function sendGet() {xhr.open("GET", "http://127.0.0.1:10086/name")xhr.setRequestHeader("Content-Type", "application/json")// 设置超时时间1000毫秒xhr.timeout = 1000xhr.addEventListener("timeout", function () {console.log("请求超时")})xhr.onload = function () {if (xhr.status === 200) {console.log(JSON.parse(xhr.responseText))}}xhr.send()
}

请求中断

xhr.abort()
// 请求中断回调
xhr.addEventListener("abort",function (){console.log("请求中断")
})

监听上传进度

// 监听上传进度
xhr.addEventListener("progress",function (event){console.log(`${(event.loaded / event.total * 100).toFixed(2)}%`)
})

Axios使用

Axios 是对 Ajax 的封装,可以帮助我们更好的发送请求,官方文档:http://www.axios-js.com/zh-cn/docs/

下面是分别发送get和post的示例

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>function axiosGet(){axios.get("http://127.0.0.1:10086/name").then(res=>{console.log(res.data)})
}function axiosPost(){axios.post("http://127.0.0.1:10086/add",{name:"张三"}).then(res=>{console.log(res.data)})
}

fetch请求

Fetch是一种网络通信协议,用于在客户端和服务器之间传输数据。该协议使用HTTP请求和响应进行通信,与传统的AJAX方式相比,Fetch更加简单易用,并提供了许多现代化的功能。

使用Fetch可以方便地向服务器发送请求,并将响应返回给客户端。你可以使用Fetch获取文本、JSON、图像和文件等数据,并进行各种处理。Fetch还支持流式传输和取消请求等高级功能,使得处理大型数据集和长时间运行的操作变得更加简单和可靠。

Fetch API也是Javascript中常用的API之一,它提供了一组方法和属性,可以在浏览器端与服务器进行通信。通过Fetch API,你可以轻松地使用Fetch协议进行数据传输,并对请求和响应进行操作和处理。

fetch 对比 xhr

fetchXMLHttpRequest(XHR)都是前端与服务器进行数据交互的常用方式,它们各有优缺点,下面是它们的比较:

  1. API 设计和使用方式

fetch 的 API 设计更加现代化、简洁和易于使用,使用起来更加直观和方便。相比之下,XHR 的 API 设计比较繁琐,需要进行多个参数的配置和回调函数的处理。

  1. 支持的请求方法

fetch API 默认只支持 GET 和 POST 请求方法,而 XHR 则支持所有标准的 HTTP 请求方法。

  1. 请求头部

fetch 中设置请求头部的方式更加清晰和直接,可以通过 Headers 对象进行设置,而 XHR 的方式相对较为繁琐。

  1. 请求体

在发送 POST 请求时,fetch API 要求将请求体数据作为参数传递给 fetch 方法中的 options 对象,而 XHR 可以直接在 send() 方法中设置请求体数据。

  1. 支持的数据类型

在解析响应数据时,fetch API 提供了多种方法,包括 .json(), .blob(), .arrayBuffer() 等,而 XHR 只支持文本和二进制数据两种数据类型。

  1. 跨域请求

在进行跨域请求时,fetch API 提供了一种简单而强大的解决方案——使用 CORS(跨域资源共享)头部实现跨域请求,而 XHR 则使用了一个叫做 XMLHttpRequest Level 2 的规范,在代码编写上相对较为繁琐。

总的来说,fetch API 与 XHR 各有优缺点,具体选择哪种方式还需要根据具体情况进行考虑。平时开发中使用较多的是 fetch ,因为它使用方便、API 简洁、语法清晰,同时也支持了大多数常用的功能,可以有效地简化前端开发流程。

fetch 返回格式

  1. text(): 将响应体解析为纯文本字符串并返回。
  2. json(): 将响应体解析为JSON格式并返回一个JavaScript对象。
  3. blob(): 将响应体解析为二进制数据并返回一个Blob对象。
  4. arrayBuffer(): 将响应体解析为二进制数据并返回一个ArrayBuffer对象。
  5. formData(): 将响应体解析为FormData对象。

发送GET请求

function fetchGet() {fetch("http://localhost:10086/name").then(res => res.json()).then(res => {console.log(res)})
}

发送POST请求

function fetchPost() {fetch("http://localhost:10086/add", {method: "post",headers:{'Content-Type':'application/json'},body: JSON.stringify({name: "张三",age: 18})}).then(res => res.json()).then(res => {console.log(res)})
}

终止请求

需要使用 AbortController 构造器

<button onclick="fetchGet()">get请求</button>
<button onclick="stop()">终止请求</button>

发送请求

const abort = new AbortController()
function fetchGet() {fetch("http://localhost:10086/name",{signal:abort.signal}).then(res => res.json()).then(res => {console.log(res)})
}

调用终止方法

function stop(){abort.abort()
}

请求超时

fetch 本身没有超时定义,需要我们自己封装一个计时器,到时间后调用 abort.abort() 方法

const abort = new AbortController()
function fetchGet() {setTimeOutFn()fetch("http://localhost:10086/name",{signal:abort.signal}).then(res => res.json()).then(res => {console.log(res)})
}function setTimeOutFn(time = 2000){setTimeout(()=>{abort.abort()},time)
}

SSE

概述

SSE(Server-Sent Events)是一种用于实现服务器主动向客户端推送数据的技术,也被称为“事件流”(Event Stream)。它基于 HTTP 协议,利用了其长连接特性,在客户端与服务器之间建立一条持久化连接,并通过这条连接实现服务器向客户端的实时数据推送。

SSE 和 Socket 区别

SSE(Server-Sent Events)和 WebSocket 都是实现服务器向客户端实时推送数据的技术,但它们在某些方面还是有一定的区别。

  1. 技术实现

SSE 基于 HTTP 协议,利用了其长连接特性,通过浏览器向服务器发送一个 HTTP 请求,建立一条持久化的连接。而 WebSocket 则是通过特殊的升级协议(HTTP/1.1 Upgrade 或者 HTTP/2)建立新的 TCP 连接,与传统 HTTP 连接不同。

  1. 数据格式

SSE 可以传输文本和二进制格式的数据,但只支持单向数据流,即只能由服务器向客户端推送数据。WebSocket 支持双向数据流,客户端和服务器可以互相发送消息,并且没有消息大小限制。

  1. 连接状态

SSE 的连接状态仅有三种:已连接、连接中、已断开。连接状态是由浏览器自动维护的,客户端无法手动关闭或重新打开连接。而 WebSocket 连接的状态更灵活,可以手动打开、关闭、重连等。

  1. 兼容性

SSE 是标准的 Web API,可以在大部分现代浏览器和移动设备上使用。但如果需要兼容老版本的浏览器(如 IE6/7/8),则需要使用 polyfill 库进行兼容。而 WebSocket 在一些老版本 Android 手机上可能存在兼容性问题,需要使用一些特殊的 API 进行处理。

  1. 安全性

SSE 的实现比较简单,都是基于 HTTP 协议的,与普通的 Web 应用没有太大差异,因此风险相对较低。WebSocket 则需要通过额外的安全措施(如 SSL/TLS 加密)来确保数据传输的安全性,避免被窃听和篡改,否则可能会带来安全隐患。

总体来说,SSE 和 WebSocket 都有各自的优缺点,适用于不同的场景和需求。如果只需要服务器向客户端单向推送数据,并且应用在前端的浏览器环境中,则 SSE 是一个更加轻量级、易于实现和维护的选择。而如果需要双向传输数据、支持自定义协议、或者在更加复杂的网络环境中应用,则 WebSocket 可能更加适合。

适用于场景

chatGPT 返回的数据 就是使用的SSE 技术

实时数据大屏 如果只是需要展示 实时的数据可以使用SSE技术 而不是非要使用webSocket

使用

调用node端写好的 sse 接口,这个接口会每隔20毫秒主动向前端发送一次数据

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<style>.content{width: 400px;height: 400px;border: 1px solid #ddd;}
</style>
<body><div class="content" id="message"></div><button onclick="start()">开始</button><button onclick="close()">关闭</button>
</body>
<script>let sse = nullfunction start(){sse = new EventSource("http://localhost:10086/ssh")// 链接成功回调sse.onopen = ()=>{console.log("open")}// 监听消息sse.onmessage = (event)=>{console.log(event)// 默认监听message,这个可以定义// 默认数据也是在event的data属性中返回document.getElementById("message").innerHTML += event.data}// 链接失败回调sse.onerror = ()=>{console.log("onerror")}}function close(){console.log("关闭")sse.close()}
</script>
</html>

WebSocket

WebSocket是双向通信,客户端可以随时向服务端发送消息,反过来服务端也可以随时向客户端发送消息

双向通信

使用node定义接口

安装

npm install ws

编写接口

const ws = require("ws")// 创建服务
const wss = new ws.Server({port:8888},()=>{console.log("socket服务启动成功")
})// 监听链接成功提示
wss.on("connection",(socket)=>{console.log("客户端链接成功")socket.on("message",e=>{// 通过e.toString()获取前端传递过来的东西socket.send("我是服务器,我收到你的消息了,内容是:"+ e.toString())})
})

调用

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<input type="text" id="msg"/>
<button onclick="send()">发送</button>
<ul id="ul"></ul>
</body>
<script>let msg = document.querySelector("#msg")let ul = document.querySelector("#ul")// 链接let wss = new WebSocket("ws://localhost:8888")// 监听消息wss.addEventListener("message", e => {console.log(e.data)let li = document.createElement("li")li.innerText = e.dataul.appendChild(li)})function send() {// 发送消息wss.send(msg.value)msg.value = ""}
</script>
</html>

消息广播

默认一个链接只会收到自己与服务器之间的消息,不能收到其他链接接收的消息,我们通过如下方式来实现

// 监听链接成功提示
wss.on("connection",(socket)=>{console.log("客户端链接成功")socket.on("message",e=>{// 广播消息 wss.clients 存放了所有链接信息,遍历这个链接信息,给所有链接者发送消息wss.clients.forEach(client=>{// 通过e.toString()获取前端传递过来的东西client.send("我是服务器,我收到你的消息了,内容是:"+ e.toString())})})
})

心跳检测

在长时间没有发送消息交互,或者网络不好的情况下,websocket 会出现断掉的情况,我们可以通过心跳检测的机制,定时发送一次消息,实现链接保活

const ws = require("ws")// 创建服务
const wss = new ws.Server({port: 8888}, () => {console.log("socket服务启动成功")
})// 消息类型
const STATE = {HEART:1,MESSAGE:2
}// 监听链接成功提示
wss.on("connection", (socket) => {console.log("客户端链接成功")socket.on("message", e => {// 广播消息wss.clients.forEach(client => {// 通过e.toString()获取前端传递过来的东西client.send(JSON.stringify({type:STATE.MESSAGE,data:"我是服务器,我收到你的消息了,内容是:" + e.toString()}))})})// 添加心跳检测let headInterval = nulllet headCheck = () => {if(socket.readyState === ws.OPEN){socket.send(JSON.stringify({type:STATE.HEART,data:"我是心跳包"}))}else{clearInterval(headInterval)}}// 每隔500毫秒检测一次setInterval(headCheck,500)
})

同时前端需要区分不同的消息类型

// 监听消息
wss.addEventListener("message", e => {let li = document.createElement("li")let data = JSON.parse(e.data)if(data.type === 2){li.innerText = data.dataul.appendChild(li)}
})

navigator.sendBeacon

使用 navigator.sendBeacon 实现高效的数据上报

在 web 开发中,我们经常需要将用户行为或性能数据上报到服务器。为了不影响用户体验,开发者通常会在页面卸载时进行数据上报。然而,传统的数据上报方式,如 XMLHttpRequestFetch API,容易受到页面卸载过程中的阻塞,导致数据丢失。为了解决这个问题,navigator.sendBeacon API 被引入,它可以在页面卸载时安全、可靠地发送数据。

navigator.sendBeacon 对比 Ajax fetch

优点

  1. 不受页面卸载过程的影响,确保数据可靠发送。
  2. 异步执行,不阻塞页面关闭或跳转。
  3. 能够发送跨域请求。

缺点

  1. fetch 和 ajax 都可以发送任意请求 而 sendBeacon 只能发送POST
  2. fetch 和 ajax 可以传输任意字节数据 而 sendBeacon 只能传送少量数据(64KB 以内)
  3. fetch 和 ajax 可以定义任意请求头 而 sendBeacon 无法自定义请求头
  4. sendBeacon 只能传输 ArrayBufferArrayBufferViewBlobDOMStringFormDataURLSearchParams 类型的数据
  5. 如果处于危险的网络环境,或者开启了广告屏蔽插件 此请求将无效

navigator.sendBeacon 应用场景

  1. 发送心跳包:可以使用 navigator.sendBeacon 发送心跳包,以保持与服务器的长连接,避免因为长时间没有网络请求而导致连接被关闭。
  2. 埋点:可以使用 navigator.sendBeacon 在页面关闭或卸载时记录用户在线时间,pv uv,以及错误日志上报 按钮点击次数。
  3. 发送用户反馈:可以使用 navigator.sendBeacon 发送用户反馈信息,如用户意见、bug 报告等,以便进行产品优化和改进

其他注意事项 type

ping请求 是html5 新增的 并且是sendBeacon 特有的 ping 请求 只能携带少量数据,并且不需要等待服务端响应,因此非常适合做埋点统计,以及日志统计相关功能。

使用方法

编写一个接口

const multer = require("multer");app.post("/ping",multer().none(),(req,res)=>{console.log(req.body.data)res.send("ok")
})

前端发送 navigation.sendBeacon 请求

function send() {let data = new FormData()data.append("data", JSON.stringify({name: "张三",age: 1}))navigator.sendBeacon("http://localhost:10086/ping", data)
}

后端接收到文件

image-20231105115637566

浏览器相应数据

image-20231105115647565

JWT鉴权

首先安装相关依赖

npm install jsonwebtoken express cors
  • jsonwebtoken:用于生成token和验证token
  • cors:处理跨域问题

接口编写

const express = require("express")
const cors = require("cors")
const jwt = require("jsonwebtoken")
const app = express()// 处理跨域问题
app.use(cors())
// 可以使用 req.body 获取post请求传递的json数据
app.use(express.json())
// token加盐
const KEY = "123456"// 白名单,包含不需要验证token的路径
const whitelist = ['/login'];
// 验证token的中间件
app.use((req, res, next) => {// 检查路径是否在白名单中if (whitelist.includes(req.path)) {console.log("3333")// 在白名单中,直接进入下一个中间件或请求处理函数next();} else {// 不在白名单中,需要验证tokenconst token = req.headers['authorization'];jwt.verify(token, KEY, (err, decode) =>{if(err){res.status(401).send('无效的token')}else{next()}})}
});// 登录接口
app.post("/login", (req, res) => {let data = req.bodyconsole.log(data)if(data.name === "admin" && data.pwd === "123456"){res.send({id:1,// 生成token,第一个参数是token携带的内容,第二是KEY,第三个是过期时间token:jwt.sign({id:1,name:data.name}, KEY, {expiresIn: "1h"})})}else{res.send({code:500,msg:"用户名或密码错误"})}
})// 获取集合信息
app.get("/list",(req,res)=>{res.send([{name:"lisi",age:1},{name:"wangwu",age:2},])
})app.listen(3000, () => {console.log("服务启动成功:http://localhost:3000")
})

前端调用

前端在发送请求时需要在请求头中携带token

login.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div>用户名: <input placeholder="用户名" id="name"/>密码: <input placeholder="密码" id="pwd"/><button onclick="login()">登录</button>
</div>
<script>function login() {let name = document.getElementById("name").value;let pwd = document.getElementById("pwd").value;axios.post("http://localhost:3000/login",{name,pwd}).then(res=>{if(res.data.token){alert("登录成功")localStorage.setItem("token",res.data.token)location.href = "./list.html"}else{alert("登录失败")localStorage.removeItem("token")}})}
</script>
</body>
</html>

list.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<button onclick="list()">获取list</button>
</body>
<script>function list(){axios.get("http://localhost:3000/list",{headers: {'authorization': localStorage.getItem("token"),}}).then(res=>{console.log(res.data)})}
</script>
</html>

判断网络状态

获取是否联网

// 是否联网,返回true或者false,true表示已经联网,false表示没有联网
console.log(navigator.onLine)

获取网络环境

前端还可以判断用户当前所在网络的好坏

// 获取网络环境
console.log(navigator.connection)

返回的是一个 NetworkInformation 对象

image-20231105203133568

image-20231105203142070

XSS跨站脚本攻击

随着互联网的快速普及,越来越多的敏感信息被存储在网络上,例如个人身份信息、财务信息等。在当前数字化时代,这些安全问题变得更加突出。作为开发者,我们必须采取适当的防范措施,以确保用户数据的安全性。本文将着重探讨跨站脚本攻击(Cross-site scripting,XSS)这一常见的网络攻击方式,包括其定义、原理、危害、分类和防范措施,以帮助大家更好地预防此类安全风险。

概述

**定义:**跨站点脚本攻击,简称XSS,是指攻击者利用网站存在的漏洞,通过在网站中注入恶意脚本代码,从而使得用户在访问该网站时受到攻击。这些恶意脚本代码通常是JavaScript 代码,它们可以窃取用户的敏感信息,如用户名、密码等,并将这些信息发送到攻击者的服务器。

原理

XSS攻击的本质是利用Web应用程序中的漏洞,向网页注入恶意脚本代码,然后将这些代码嵌入到网页中,当其他用户访问这个网页时,恶意脚本将会被执行。

攻击者通常会在Web应用程序的输入框、评论框、搜索框等可输入内容的地方输入特定的脚本代码,这些代码可以被Web应用程序直接插入到网页中,导致网页上的所有用户都会受到攻击。

XSS攻击的原理包括以下几个步骤:

1、攻击者在Web应用程序的输入框、评论框等可输入内容的地方输入包含script标签的恶意脚本代码,例如:

<script>
// 在这里插入恶意脚本代码
</script>

2、Web应用程序将恶意脚本代码保存到数据库中或直接将其插入到网页的HTML代码中。

3、当其他用户访问这个网页时,浏览器会执行其中的恶意脚本代码。恶意脚本可以窃取用户的敏感信息,如登录凭证、浏览器历史记录、Cookie等,或者通过控制用户的浏览器来进行更多的攻击。

例如,以下是一段可以窃取用户Cookie的恶意脚本代码:

<script>
let cookieValue = document.cookie;
// 将cookieValue发送到攻击者的服务器
</script>

4、攻击者获取到用户的敏感信息后,可以进行更进一步的攻击,例如重定向到恶意网站、发起钓鱼攻击等。

预防工具

使用第三方库来预防,这里使用 xss,官网文档:https://www.npmjs.com/package/xss

<script src="https://rawgit.com/leizongmin/js-xss/master/dist/xss.js"></script>
<script>// apply function filterXSS in the same wayvar html = filterXSS('<script>alert("xss");</scr' + "ipt>");alert(html);
</script>

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

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

相关文章

分治法——找众数

分治法——找众数 要求&#xff1a; 寻找整数数组的众数&#xff0c;如果存在多个众数&#xff0c;则返回权值最小的那个 第一步&#xff1a; 要利用分治法找众数&#xff0c;首先就先要使数组有序。这里&#xff0c;我们用C语言库中的qsort进行快排&#xff1a; qsort(nums…

flink的安装与使用(ubuntu)

组件版本 虚拟机&#xff1a;ubuntu-20.04.6-live-server-amd64.iso flink&#xff1a;flink-1.18.0-bin-scala_2.12.tgz jdk&#xff1a;jdk-8u291-linux-x64.tar flink 下载 1、官网&#xff1a;https://flink.apache.org/downloads/ 2、清华镜像&#xff1a;https://mirr…

ICP学习记录

1. 流程图 ICP&#xff08;一&#xff09;原理详解_icp原理-CSDN博客 ICP算法详解——我见过最清晰的解释-CSDN博客 ICP算法理解-CSDN博客 ICP知识点梳理笔记_icp非凸_KalutSirocco的博客-CSDN博客 【精选】【图像配准】点云配准ICP算法介绍&#xff1a;基础流程、ICP算法…

基于SSM的社区智慧养老监护管理平台

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

opencv复习(简短的一次印象记录)

2-高斯与中值滤波_哔哩哔哩_bilibili 1、均值滤波 2、高斯滤波 3、中值滤波 4、腐蚀操作 卷积核不都是255就腐蚀掉 5、膨胀操作 6、开运算 先腐蚀再膨胀 7、闭运算 先膨胀再腐蚀 8、礼帽 原始数据-开运算结果 9、黑帽 闭运算结果-原始数据 10、Sobel算子 左-右&#x…

【工具】Github统计代码行数工具推荐(VScode插件、兼容任何平台、不用下载安装包)

需求&#xff1a; 1&#xff09;被要求统计代码行数&#xff1b; 2&#xff09;不想打开Linux&#xff0c;懒得下载Windows版本GitStats&#xff1b; 3&#xff09;打开了Linux但也不记得find命令行怎么用&#xff1b; 4&#xff09;打开了Linux&#xff0c;装好了Gitstats但自…

解决gtihub访问不到的

解决gtihub访问不到的 小编一开始也是找不到git但是通过查询资料&#xff0c;最终也是找到了解决方式 据说git的ip地址通常会变化的&#xff0c;可以通过地址查询网站查询到git当前的ip https://sites.ipaddress.com/github.com/在输入框中github.com&#xff0c;然后搜索 在…

Linux笔记-对/dev/vda1和/dev/vda2的理解

首先是这张图&#xff1a; 对于&#xff1a; /dev/vda1和/dev/vda2 可以知道&#xff0c;这个机器是在虚拟机上的&#xff0c;从设备描述中可以看到&#xff0c;与IO有关。 问下ChatGPT 问&#xff1a;linux上 /dev/vda1 和 /dev/vda2是干嘛的 答&#xff1a; /dev/vda1和…

MATLAB和西门子SMART PLC UDP通信

MATLAB和SMART PLC的OPC通信请参考下面文章链接,这里不再赘述: MATLAB和西门子SMART PLC OPC通信-CSDN博客文章浏览阅读661次,点赞26次,收藏2次。西门子S7-200SMART PLC OPC软件的下载和使用,请查看下面文章Smart 200PLC PC Access SMART OPC通信_基于pc access smart的o…

制造行业数字化运维破局之道

项目背景 某大型汽车制造集团&#xff0c;致力于通过数字化、智能化运营手段为用户提升提供高品质的汽车产品和服务。IT部门不仅为内外部持续提供服务&#xff0c;同时为业务运营与核心系统运行提供重要支撑。数字化运维作为数字化转型的核心基础&#xff0c;不但要保障数据安…

使用 curator 连接 zookeeper 集群 Invalid config event received

dubbo整合zookeeper 如图&#xff0c;错误日志 2023-11-04 21:16:18.699 ERROR 7459 [main-EventThread] org.apache.curator.framework.imps.EnsembleTracker Caller0 at org.apache.curator.framework.imps.EnsembleTracker.processConfigData(EnsembleTracker.java…

Redis之Java操作Redis的使用

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是君易--鑨&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的博客专栏《Redis实战开发》。&#x1f3af;&#x1f3af; …