優(yōu)化方案數(shù)學(xué)2023版電子版seo中文意思
網(wǎng)絡(luò)請求
node編寫接口
這里用到的幾個(gè)包的作用
- express:基于 Node.js 平臺(tái),快速、開放、極簡的 Web 開發(fā)框架,官網(wǎng):https://www.expressjs.com.cn/
- cors:用來解決跨域問題
- body-parser:可以通過 req.body 獲取post請求傳遞過來的json數(shù)據(jù)
- 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())
// 設(shè)置上傳目錄和文件名
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參數(shù)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// 設(shè)置每隔20毫秒主動(dòng)發(fā)送一次數(shù)據(jù)let timer = setInterval(()=>{if(current >= arr.length){clearInterval(timer)}else{// 發(fā)送消息必須是 data: 開頭,\n\n 結(jié)尾。中間是發(fā)送的內(nèi)容,內(nèi)容必須是一個(gè)字符串res.write(`data:${arr[current]}\n\n`)current++}},20)
})app.listen(10086, () =>{console.log("啟動(dòng)成功: http://localhost:10086")
})
Ajax請求
發(fā)送GET請求
let xhr = new XMLHttpRequest()
function sendGet(){xhr.open("GET","http://127.0.0.1:10086/name")// 當(dāng)接口相應(yīng)數(shù)據(jù)后會(huì)觸發(fā)onload回調(diào)xhr.onload = function (){if(xhr.status === 200){console.log(JSON.parse(xhr.responseText))}}xhr.send()
}
發(fā)送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))}}// 定義發(fā)送給后端的數(shù)據(jù)let data = {name:"張三",age:18}// 把數(shù)據(jù)放在send中進(jìn)行發(fā)送,需要使用JSON.stringify進(jìn)行序列化xhr.send(JSON.stringify(data))
}
上傳文件
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)
})
設(shè)置超時(shí)時(shí)間
function sendGet() {xhr.open("GET", "http://127.0.0.1:10086/name")xhr.setRequestHeader("Content-Type", "application/json")// 設(shè)置超時(shí)時(shí)間1000毫秒xhr.timeout = 1000xhr.addEventListener("timeout", function () {console.log("請求超時(shí)")})xhr.onload = function () {if (xhr.status === 200) {console.log(JSON.parse(xhr.responseText))}}xhr.send()
}
請求中斷
xhr.abort()
// 請求中斷回調(diào)
xhr.addEventListener("abort",function (){console.log("請求中斷")
})
監(jiān)聽上傳進(jìn)度
// 監(jiān)聽上傳進(jìn)度
xhr.addEventListener("progress",function (event){console.log(`${(event.loaded / event.total * 100).toFixed(2)}%`)
})
Axios使用
Axios 是對 Ajax 的封裝,可以幫助我們更好的發(fā)送請求,官方文檔:http://www.axios-js.com/zh-cn/docs/
下面是分別發(fā)送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是一種網(wǎng)絡(luò)通信協(xié)議,用于在客戶端和服務(wù)器之間傳輸數(shù)據(jù)。該協(xié)議使用HTTP請求和響應(yīng)進(jìn)行通信,與傳統(tǒng)的AJAX方式相比,Fetch更加簡單易用,并提供了許多現(xiàn)代化的功能。
使用Fetch可以方便地向服務(wù)器發(fā)送請求,并將響應(yīng)返回給客戶端。你可以使用Fetch獲取文本、JSON、圖像和文件等數(shù)據(jù),并進(jìn)行各種處理。Fetch還支持流式傳輸和取消請求等高級功能,使得處理大型數(shù)據(jù)集和長時(shí)間運(yùn)行的操作變得更加簡單和可靠。
Fetch API也是Javascript中常用的API之一,它提供了一組方法和屬性,可以在瀏覽器端與服務(wù)器進(jìn)行通信。通過Fetch API,你可以輕松地使用Fetch協(xié)議進(jìn)行數(shù)據(jù)傳輸,并對請求和響應(yīng)進(jìn)行操作和處理。
fetch 對比 xhr
fetch
和 XMLHttpRequest
(XHR)都是前端與服務(wù)器進(jìn)行數(shù)據(jù)交互的常用方式,它們各有優(yōu)缺點(diǎn),下面是它們的比較:
- API 設(shè)計(jì)和使用方式
fetch
的 API 設(shè)計(jì)更加現(xiàn)代化、簡潔和易于使用,使用起來更加直觀和方便。相比之下,XHR 的 API 設(shè)計(jì)比較繁瑣,需要進(jìn)行多個(gè)參數(shù)的配置和回調(diào)函數(shù)的處理。
- 支持的請求方法
fetch
API 默認(rèn)只支持 GET 和 POST 請求方法,而 XHR 則支持所有標(biāo)準(zhǔn)的 HTTP 請求方法。
- 請求頭部
在 fetch
中設(shè)置請求頭部的方式更加清晰和直接,可以通過 Headers
對象進(jìn)行設(shè)置,而 XHR 的方式相對較為繁瑣。
- 請求體
在發(fā)送 POST 請求時(shí),fetch
API 要求將請求體數(shù)據(jù)作為參數(shù)傳遞給 fetch
方法中的 options
對象,而 XHR 可以直接在 send()
方法中設(shè)置請求體數(shù)據(jù)。
- 支持的數(shù)據(jù)類型
在解析響應(yīng)數(shù)據(jù)時(shí),fetch
API 提供了多種方法,包括 .json()
, .blob()
, .arrayBuffer()
等,而 XHR 只支持文本和二進(jìn)制數(shù)據(jù)兩種數(shù)據(jù)類型。
- 跨域請求
在進(jìn)行跨域請求時(shí),fetch
API 提供了一種簡單而強(qiáng)大的解決方案——使用 CORS(跨域資源共享)頭部實(shí)現(xiàn)跨域請求,而 XHR 則使用了一個(gè)叫做 XMLHttpRequest Level 2
的規(guī)范,在代碼編寫上相對較為繁瑣。
總的來說,fetch
API 與 XHR 各有優(yōu)缺點(diǎn),具體選擇哪種方式還需要根據(jù)具體情況進(jìn)行考慮。平時(shí)開發(fā)中使用較多的是 fetch
,因?yàn)樗褂梅奖?、API 簡潔、語法清晰,同時(shí)也支持了大多數(shù)常用的功能,可以有效地簡化前端開發(fā)流程。
fetch 返回格式
- text(): 將響應(yīng)體解析為純文本字符串并返回。
- json(): 將響應(yīng)體解析為JSON格式并返回一個(gè)JavaScript對象。
- blob(): 將響應(yīng)體解析為二進(jìn)制數(shù)據(jù)并返回一個(gè)Blob對象。
- arrayBuffer(): 將響應(yīng)體解析為二進(jìn)制數(shù)據(jù)并返回一個(gè)ArrayBuffer對象。
- formData(): 將響應(yīng)體解析為FormData對象。
發(fā)送GET請求
function fetchGet() {fetch("http://localhost:10086/name").then(res => res.json()).then(res => {console.log(res)})
}
發(fā)送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 構(gòu)造器
<button onclick="fetchGet()">get請求</button>
<button onclick="stop()">終止請求</button>
發(fā)送請求
const abort = new AbortController()
function fetchGet() {fetch("http://localhost:10086/name",{signal:abort.signal}).then(res => res.json()).then(res => {console.log(res)})
}
調(diào)用終止方法
function stop(){abort.abort()
}
請求超時(shí)
fetch 本身沒有超時(shí)定義,需要我們自己封裝一個(gè)計(jì)時(shí)器,到時(shí)間后調(diào)用 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)是一種用于實(shí)現(xiàn)服務(wù)器主動(dòng)向客戶端推送數(shù)據(jù)的技術(shù),也被稱為“事件流”(Event Stream)。它基于 HTTP 協(xié)議,利用了其長連接特性,在客戶端與服務(wù)器之間建立一條持久化連接,并通過這條連接實(shí)現(xiàn)服務(wù)器向客戶端的實(shí)時(shí)數(shù)據(jù)推送。
SSE 和 Socket 區(qū)別
SSE(Server-Sent Events)和 WebSocket 都是實(shí)現(xiàn)服務(wù)器向客戶端實(shí)時(shí)推送數(shù)據(jù)的技術(shù),但它們在某些方面還是有一定的區(qū)別。
- 技術(shù)實(shí)現(xiàn)
SSE 基于 HTTP 協(xié)議,利用了其長連接特性,通過瀏覽器向服務(wù)器發(fā)送一個(gè) HTTP 請求,建立一條持久化的連接。而 WebSocket 則是通過特殊的升級協(xié)議(HTTP/1.1 Upgrade 或者 HTTP/2)建立新的 TCP 連接,與傳統(tǒng) HTTP 連接不同。
- 數(shù)據(jù)格式
SSE 可以傳輸文本和二進(jìn)制格式的數(shù)據(jù),但只支持單向數(shù)據(jù)流,即只能由服務(wù)器向客戶端推送數(shù)據(jù)。WebSocket 支持雙向數(shù)據(jù)流,客戶端和服務(wù)器可以互相發(fā)送消息,并且沒有消息大小限制。
- 連接狀態(tài)
SSE 的連接狀態(tài)僅有三種:已連接、連接中、已斷開。連接狀態(tài)是由瀏覽器自動(dòng)維護(hù)的,客戶端無法手動(dòng)關(guān)閉或重新打開連接。而 WebSocket 連接的狀態(tài)更靈活,可以手動(dòng)打開、關(guān)閉、重連等。
- 兼容性
SSE 是標(biāo)準(zhǔn)的 Web API,可以在大部分現(xiàn)代瀏覽器和移動(dòng)設(shè)備上使用。但如果需要兼容老版本的瀏覽器(如 IE6/7/8),則需要使用 polyfill 庫進(jìn)行兼容。而 WebSocket 在一些老版本 Android 手機(jī)上可能存在兼容性問題,需要使用一些特殊的 API 進(jìn)行處理。
- 安全性
SSE 的實(shí)現(xiàn)比較簡單,都是基于 HTTP 協(xié)議的,與普通的 Web 應(yīng)用沒有太大差異,因此風(fēng)險(xiǎn)相對較低。WebSocket 則需要通過額外的安全措施(如 SSL/TLS 加密)來確保數(shù)據(jù)傳輸?shù)陌踩?#xff0c;避免被竊聽和篡改,否則可能會(huì)帶來安全隱患。
總體來說,SSE 和 WebSocket 都有各自的優(yōu)缺點(diǎn),適用于不同的場景和需求。如果只需要服務(wù)器向客戶端單向推送數(shù)據(jù),并且應(yīng)用在前端的瀏覽器環(huán)境中,則 SSE 是一個(gè)更加輕量級、易于實(shí)現(xiàn)和維護(hù)的選擇。而如果需要雙向傳輸數(shù)據(jù)、支持自定義協(xié)議、或者在更加復(fù)雜的網(wǎng)絡(luò)環(huán)境中應(yīng)用,則 WebSocket 可能更加適合。
適用于場景
chatGPT 返回的數(shù)據(jù) 就是使用的SSE 技術(shù)
實(shí)時(shí)數(shù)據(jù)大屏 如果只是需要展示 實(shí)時(shí)的數(shù)據(jù)可以使用SSE技術(shù) 而不是非要使用webSocket
使用
調(diào)用node端寫好的 sse 接口,這個(gè)接口會(huì)每隔20毫秒主動(dòng)向前端發(fā)送一次數(shù)據(jù)
<!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()">關(guān)閉</button>
</body>
<script>let sse = nullfunction start(){sse = new EventSource("http://localhost:10086/ssh")// 鏈接成功回調(diào)sse.onopen = ()=>{console.log("open")}// 監(jiān)聽消息sse.onmessage = (event)=>{console.log(event)// 默認(rèn)監(jiān)聽message,這個(gè)可以定義// 默認(rèn)數(shù)據(jù)也是在event的data屬性中返回document.getElementById("message").innerHTML += event.data}// 鏈接失敗回調(diào)sse.onerror = ()=>{console.log("onerror")}}function close(){console.log("關(guān)閉")sse.close()}
</script>
</html>
WebSocket
WebSocket是雙向通信,客戶端可以隨時(shí)向服務(wù)端發(fā)送消息,反過來服務(wù)端也可以隨時(shí)向客戶端發(fā)送消息
雙向通信
使用node定義接口
安裝
npm install ws
編寫接口
const ws = require("ws")// 創(chuàng)建服務(wù)
const wss = new ws.Server({port:8888},()=>{console.log("socket服務(wù)啟動(dòng)成功")
})// 監(jiān)聽鏈接成功提示
wss.on("connection",(socket)=>{console.log("客戶端鏈接成功")socket.on("message",e=>{// 通過e.toString()獲取前端傳遞過來的東西socket.send("我是服務(wù)器,我收到你的消息了,內(nèi)容是:"+ e.toString())})
})
調(diào)用
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<input type="text" id="msg"/>
<button onclick="send()">發(fā)送</button>
<ul id="ul"></ul>
</body>
<script>let msg = document.querySelector("#msg")let ul = document.querySelector("#ul")// 鏈接let wss = new WebSocket("ws://localhost:8888")// 監(jiān)聽消息wss.addEventListener("message", e => {console.log(e.data)let li = document.createElement("li")li.innerText = e.dataul.appendChild(li)})function send() {// 發(fā)送消息wss.send(msg.value)msg.value = ""}
</script>
</html>
消息廣播
默認(rèn)一個(gè)鏈接只會(huì)收到自己與服務(wù)器之間的消息,不能收到其他鏈接接收的消息,我們通過如下方式來實(shí)現(xiàn)
// 監(jiān)聽鏈接成功提示
wss.on("connection",(socket)=>{console.log("客戶端鏈接成功")socket.on("message",e=>{// 廣播消息 wss.clients 存放了所有鏈接信息,遍歷這個(gè)鏈接信息,給所有鏈接者發(fā)送消息wss.clients.forEach(client=>{// 通過e.toString()獲取前端傳遞過來的東西client.send("我是服務(wù)器,我收到你的消息了,內(nèi)容是:"+ e.toString())})})
})
心跳檢測
在長時(shí)間沒有發(fā)送消息交互,或者網(wǎng)絡(luò)不好的情況下,websocket 會(huì)出現(xiàn)斷掉的情況,我們可以通過心跳檢測的機(jī)制,定時(shí)發(fā)送一次消息,實(shí)現(xiàn)鏈接保活
const ws = require("ws")// 創(chuàng)建服務(wù)
const wss = new ws.Server({port: 8888}, () => {console.log("socket服務(wù)啟動(dòng)成功")
})// 消息類型
const STATE = {HEART:1,MESSAGE:2
}// 監(jiān)聽鏈接成功提示
wss.on("connection", (socket) => {console.log("客戶端鏈接成功")socket.on("message", e => {// 廣播消息wss.clients.forEach(client => {// 通過e.toString()獲取前端傳遞過來的東西client.send(JSON.stringify({type:STATE.MESSAGE,data:"我是服務(wù)器,我收到你的消息了,內(nèi)容是:" + 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)
})
同時(shí)前端需要區(qū)分不同的消息類型
// 監(jiān)聽消息
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
實(shí)現(xiàn)高效的數(shù)據(jù)上報(bào)
在 web 開發(fā)中,我們經(jīng)常需要將用戶行為或性能數(shù)據(jù)上報(bào)到服務(wù)器。為了不影響用戶體驗(yàn),開發(fā)者通常會(huì)在頁面卸載時(shí)進(jìn)行數(shù)據(jù)上報(bào)。然而,傳統(tǒng)的數(shù)據(jù)上報(bào)方式,如 XMLHttpRequest
或 Fetch API
,容易受到頁面卸載過程中的阻塞,導(dǎo)致數(shù)據(jù)丟失。為了解決這個(gè)問題,navigator.sendBeacon
API 被引入,它可以在頁面卸載時(shí)安全、可靠地發(fā)送數(shù)據(jù)。
navigator.sendBeacon
對比 Ajax fetch
優(yōu)點(diǎn)
- 不受頁面卸載過程的影響,確保數(shù)據(jù)可靠發(fā)送。
- 異步執(zhí)行,不阻塞頁面關(guān)閉或跳轉(zhuǎn)。
- 能夠發(fā)送跨域請求。
缺點(diǎn)
- fetch 和 ajax 都可以發(fā)送任意請求 而 sendBeacon 只能發(fā)送POST
- fetch 和 ajax 可以傳輸任意字節(jié)數(shù)據(jù) 而 sendBeacon 只能傳送少量數(shù)據(jù)(64KB 以內(nèi))
- fetch 和 ajax 可以定義任意請求頭 而 sendBeacon 無法自定義請求頭
- sendBeacon 只能傳輸
ArrayBuffer
、ArrayBufferView
、Blob
、DOMString
、FormData
或URLSearchParams
類型的數(shù)據(jù) - 如果處于危險(xiǎn)的網(wǎng)絡(luò)環(huán)境,或者開啟了廣告屏蔽插件 此請求將無效
navigator.sendBeacon
應(yīng)用場景
- 發(fā)送心跳包:可以使用
navigator.sendBeacon
發(fā)送心跳包,以保持與服務(wù)器的長連接,避免因?yàn)殚L時(shí)間沒有網(wǎng)絡(luò)請求而導(dǎo)致連接被關(guān)閉。 - 埋點(diǎn):可以使用
navigator.sendBeacon
在頁面關(guān)閉或卸載時(shí)記錄用戶在線時(shí)間,pv uv,以及錯(cuò)誤日志上報(bào) 按鈕點(diǎn)擊次數(shù)。 - 發(fā)送用戶反饋:可以使用
navigator.sendBeacon
發(fā)送用戶反饋信息,如用戶意見、bug 報(bào)告等,以便進(jìn)行產(chǎn)品優(yōu)化和改進(jìn)
其他注意事項(xiàng) type
ping請求 是html5 新增的 并且是sendBeacon 特有的 ping 請求 只能攜帶少量數(shù)據(jù),并且不需要等待服務(wù)端響應(yīng),因此非常適合做埋點(diǎn)統(tǒng)計(jì),以及日志統(tǒng)計(jì)相關(guān)功能。
使用方法
編寫一個(gè)接口
const multer = require("multer");app.post("/ping",multer().none(),(req,res)=>{console.log(req.body.data)res.send("ok")
})
前端發(fā)送 navigation.sendBeacon 請求
function send() {let data = new FormData()data.append("data", JSON.stringify({name: "張三",age: 1}))navigator.sendBeacon("http://localhost:10086/ping", data)
}
后端接收到文件
瀏覽器相應(yīng)數(shù)據(jù)
JWT鑒權(quán)
首先安裝相關(guān)依賴
npm install jsonwebtoken express cors
- jsonwebtoken:用于生成token和驗(yàn)證token
- cors:處理跨域問題
接口編寫
const express = require("express")
const cors = require("cors")
const jwt = require("jsonwebtoken")
const app = express()// 處理跨域問題
app.use(cors())
// 可以使用 req.body 獲取post請求傳遞的json數(shù)據(jù)
app.use(express.json())
// token加鹽
const KEY = "123456"// 白名單,包含不需要驗(yàn)證token的路徑
const whitelist = ['/login'];
// 驗(yàn)證token的中間件
app.use((req, res, next) => {// 檢查路徑是否在白名單中if (whitelist.includes(req.path)) {console.log("3333")// 在白名單中,直接進(jìn)入下一個(gè)中間件或請求處理函數(shù)next();} else {// 不在白名單中,需要驗(yàn)證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,第一個(gè)參數(shù)是token攜帶的內(nèi)容,第二是KEY,第三個(gè)是過期時(shí)間token:jwt.sign({id:1,name:data.name}, KEY, {expiresIn: "1h"})})}else{res.send({code:500,msg:"用戶名或密碼錯(cuò)誤"})}
})// 獲取集合信息
app.get("/list",(req,res)=>{res.send([{name:"lisi",age:1},{name:"wangwu",age:2},])
})app.listen(3000, () => {console.log("服務(wù)啟動(dòng)成功:http://localhost:3000")
})
前端調(diào)用
前端在發(fā)送請求時(shí)需要在請求頭中攜帶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>
判斷網(wǎng)絡(luò)狀態(tài)
獲取是否聯(lián)網(wǎng)
// 是否聯(lián)網(wǎng),返回true或者false,true表示已經(jīng)聯(lián)網(wǎng),false表示沒有聯(lián)網(wǎng)
console.log(navigator.onLine)
獲取網(wǎng)絡(luò)環(huán)境
前端還可以判斷用戶當(dāng)前所在網(wǎng)絡(luò)的好壞
// 獲取網(wǎng)絡(luò)環(huán)境
console.log(navigator.connection)
返回的是一個(gè) NetworkInformation 對象
XSS跨站腳本攻擊
隨著互聯(lián)網(wǎng)的快速普及,越來越多的敏感信息被存儲(chǔ)在網(wǎng)絡(luò)上,例如個(gè)人身份信息、財(cái)務(wù)信息等。在當(dāng)前數(shù)字化時(shí)代,這些安全問題變得更加突出。作為開發(fā)者,我們必須采取適當(dāng)?shù)姆婪洞胧?#xff0c;以確保用戶數(shù)據(jù)的安全性。本文將著重探討跨站腳本攻擊(Cross-site scripting,XSS)這一常見的網(wǎng)絡(luò)攻擊方式,包括其定義、原理、危害、分類和防范措施,以幫助大家更好地預(yù)防此類安全風(fēng)險(xiǎn)。
概述
**定義:**跨站點(diǎn)腳本攻擊,簡稱XSS,是指攻擊者利用網(wǎng)站存在的漏洞,通過在網(wǎng)站中注入惡意腳本代碼,從而使得用戶在訪問該網(wǎng)站時(shí)受到攻擊。這些惡意腳本代碼通常是JavaScript 代碼,它們可以竊取用戶的敏感信息,如用戶名、密碼等,并將這些信息發(fā)送到攻擊者的服務(wù)器。
原理
XSS攻擊的本質(zhì)是利用Web應(yīng)用程序中的漏洞,向網(wǎng)頁注入惡意腳本代碼,然后將這些代碼嵌入到網(wǎng)頁中,當(dāng)其他用戶訪問這個(gè)網(wǎng)頁時(shí),惡意腳本將會(huì)被執(zhí)行。
攻擊者通常會(huì)在Web應(yīng)用程序的輸入框、評論框、搜索框等可輸入內(nèi)容的地方輸入特定的腳本代碼,這些代碼可以被Web應(yīng)用程序直接插入到網(wǎng)頁中,導(dǎo)致網(wǎng)頁上的所有用戶都會(huì)受到攻擊。
XSS攻擊的原理包括以下幾個(gè)步驟:
1、攻擊者在Web應(yīng)用程序的輸入框、評論框等可輸入內(nèi)容的地方輸入包含script標(biāo)簽的惡意腳本代碼,例如:
<script>
// 在這里插入惡意腳本代碼
</script>
2、Web應(yīng)用程序?qū)阂饽_本代碼保存到數(shù)據(jù)庫中或直接將其插入到網(wǎng)頁的HTML代碼中。
3、當(dāng)其他用戶訪問這個(gè)網(wǎng)頁時(shí),瀏覽器會(huì)執(zhí)行其中的惡意腳本代碼。惡意腳本可以竊取用戶的敏感信息,如登錄憑證、瀏覽器歷史記錄、Cookie等,或者通過控制用戶的瀏覽器來進(jìn)行更多的攻擊。
例如,以下是一段可以竊取用戶Cookie的惡意腳本代碼:
<script>
let cookieValue = document.cookie;
// 將cookieValue發(fā)送到攻擊者的服務(wù)器
</script>
4、攻擊者獲取到用戶的敏感信息后,可以進(jìn)行更進(jìn)一步的攻擊,例如重定向到惡意網(wǎng)站、發(fā)起釣魚攻擊等。
預(yù)防工具
使用第三方庫來預(yù)防,這里使用 xss,官網(wǎng)文檔: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>