描述
長連接(Keep-Alive)是一種HTTP/1.1的持久連接技術(shù),它允許客戶端和服務(wù)器在一次TCP連接上進行多個HTTP請求和響應(yīng),而不必為每個請求/響應(yīng)建立和斷開一個新的連接。長連接有助于減少服務(wù)器的負載和提高性能。
長連接的HTTP請求方法與普通HTTP請求方法相同,可以使用GET、POST、PUT、DELETE等HTTP請求方法。但是,在發(fā)送HTTP響應(yīng)之前時,需要設(shè)置"Connection: keep-alive"請求頭,以指示客戶端希望與服務(wù)器建立長連接。服務(wù)器發(fā)送事件(Server-Sent Events,簡稱SSE)就是為了解決這個問題,而提出的一種新API,部署在EventSource對象上。目前,除了IE,其他主流瀏覽器都支持。而客戶端(瀏覽器)是使用HTML5的EventSource。
SSE與WebSocket有相似功能,都是用來建立瀏覽器與服務(wù)器之間的通信渠道。兩者的區(qū)別在于:
-
WebSocket是全雙工通道,可以雙向通信,功能更強;SSE是單向通道,只能服務(wù)器向瀏覽器端發(fā)送。
-
WebSocket是一個新的協(xié)議,需要服務(wù)器端支持;SSE則是部署在HTTP協(xié)議之上的,現(xiàn)有的服務(wù)器軟件都支持。
-
SSE是一個輕量級協(xié)議,相對簡單;WebSocket是一種較重的協(xié)議,相對復(fù)雜。
-
SSE默認支持斷線重連,WebSocket則需要額外部署。
-
SSE支持自定義發(fā)送的數(shù)據(jù)類型。
從上面的比較可以看出,兩者各有特點,適合不同的場合。
客戶端代碼
建立連接
- 首先,瀏覽器向服務(wù)器發(fā)起連接,生成一個EventSource的實例對象。
- 新生成的EventSource實例對象,有一個readyState屬性,表明連接所處的狀態(tài)。
它可以取以下值:
0,相當于常量EventSource.CONNECTING,表示連接還未建立,或者連接斷線。
1,相當于常量EventSource.OPEN,表示連接已經(jīng)建立,可以接受數(shù)據(jù)。
2,相當于常量EventSource.CLOSED,表示連接已斷,且不會重連。
open事件 連接一旦建立,就會觸發(fā)open事件,可以定義相應(yīng)的回調(diào)函數(shù)。
message事件 收到數(shù)據(jù)就會觸發(fā)message事件。
參數(shù)對象event有如下屬性:
data:服務(wù)器端傳回的數(shù)據(jù)(文本格式)。
origin: 服務(wù)器端URL的域名部分,即協(xié)議、域名和端口。
lastEventId:數(shù)據(jù)的編號,由服務(wù)器端發(fā)送。如果沒有編號,這個屬性為空。
error事件 如果發(fā)生通信錯誤(比如連接中斷),就會觸發(fā)error事件。
let source = ''
if (!!window.EventSource) {
source = new EventSource('http://localhost:8088/sses/');
}
source.onopen = function(event) {
// handle open event
console.log(source.readyState);
console.log("長連接打開");
};
source.onmessage = function(event) {
console.log(event);
console.log(JSON.parse(event.data));
console.log(source.readyState);
console.log("收到長連接信息");
};
source.onerror = function(event) {
console.log(source.readyState);
console.log("長連接中斷");
// source.close();
};
設(shè)置SSE的請求頭。
在使用 EventSource 對象時,可以設(shè)置請求頭來指定一些額外的參數(shù)。這些參數(shù)通常用于告訴服務(wù)器如何處理 SSE 請求,或者用于進行身份驗證等操作。
要設(shè)置請求頭,可以在創(chuàng)建 EventSource 對象時傳入一個配置對象,例如:
const eventSource = new EventSource('/sse', {
withCredentials: true,
headers: {
'Authorization': 'Bearer xxxxx',
'X-Custom-Header': 'value'
}
});
在上面的代碼中,我們設(shè)置了 withCredentials 參數(shù)為 true,表示 SSE 請求會攜帶跨域身份驗證信息(如果有的話)。我們還設(shè)置了 Authorization 和 X-Custom-Header 兩個請求頭,分別用于傳遞身份驗證令牌和自定義參數(shù)。
除了上面這些常用的請求頭之外,還有一些其他的請求頭可以使用,例如:
Last-Event-ID
:用于指定上一次接收到的 SSE 事件的 ID,以便服務(wù)器可以發(fā)送新的事件。Cache-Control
:用于控制 SSE 請求的緩存策略。Connection
:用于指定 SSE 請求的連接類型,通常設(shè)置為 keep-alive。Accept
:用于指定客戶端可以接受的 SSE 數(shù)據(jù)類型。
需要注意的是,并非所有的請求頭都被所有瀏覽器和服務(wù)器支持。在使用時需要查看相關(guān)文檔以確定是否可用。
-
withCredentials
是 XMLHttpRequest 對象的一個屬性,用于指定跨域請求時是否攜帶身份驗證信息(如 cookie、HTTP 認證等)。 - 默認情況下,跨域請求不會攜帶身份驗證信息,因為這可能會帶來安全風(fēng)險。但在某些情況下,我們需要在跨域請求中攜帶身份驗證信息,例如向服務(wù)器發(fā)送用戶認證憑證等。這時就可以通過設(shè)置 withCredentials 屬性來讓瀏覽器攜帶身份驗證信息。
- 當
withCredentials
設(shè)置為 true 時,瀏覽器會在請求頭中添加一個 Cookie 字段或者 Authorization 字段(如果使用 HTTP 認證)。這樣服務(wù)器就可以識別當前請求的用戶身份,并進行相應(yīng)的處理。需要注意的是,如果服務(wù)器沒有明確允許跨域請求攜帶身份驗證信息,那么瀏覽器仍然不會發(fā)送身份驗證信息。 - 在 SSE 請求中,withCredentials 與 XMLHttpRequest 對象中的用法相同,用于指定 SSE 請求是否攜帶跨域身份驗證信息。如果需要在 SSE 請求中攜帶身份驗證信息,就需要將 withCredentials 設(shè)置為 true。
curl是一款常用的命令行工具
curl是一款常用的命令行工具,它支持多種協(xié)議,包括HTTP、HTTPS、FTP、SMTP等,可以用來發(fā)送HTTP請求、下載文件、上傳文件等。curl可以在命令行中使用,也可以在腳本中作為庫來使用。
使用curl,可以向服務(wù)器發(fā)送HTTP請求并接收響應(yīng),然后將響應(yīng)內(nèi)容顯示在命令行中,或者將其保存到文件中。curl可以設(shè)置請求頭、請求方法、請求體等HTTP請求參數(shù),還支持代理、Cookie、SSL等特性。
以下是一個使用curl發(fā)送GET請求并保存響應(yīng)內(nèi)容到文件的示例:
curl -o response.txt https://example.com
nodejs服務(wù)端
const express = require('express');
const Aixpor = require("./options")
const app = express()
const port = 8088
//設(shè)置跨域訪問
app.all("*", function(req, res, next) {
//設(shè)置允許跨域的域名,*代表允許任意域名跨域
res.header("Access-Control-Allow-Origin", req.headers.origin || '*');
// //只允許http://xxx.xx.xx/可跨
//res.header('Access-Control-Allow-Origin', 'http://xxx.xx.xx/');
//允許的header類型
res.header("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With");
//跨域允許的請求方式
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
// 可以帶cookies
res.header("Access-Control-Allow-Credentials", true);
if (req.method == 'OPTIONS') {
res.sendStatus(200);
} else {
next();
}
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
//實現(xiàn)接口
Aixpor.List(app);
Aixpor.Longstream(app);
//寫個接口list
const List = function(app){
var data = [{
label: '早晨',
value: '面條'
},
{
label: '中午',
value: '煎餅'
}
];
app.get('/list', function(req, res) {
res.status(200);
res.json(data);
});
}
//長連接接口
const Longstream = function(app){
var data = [{
label: '早晨',
value: '面條'
},
{
label: '中午',
value: '煎餅'
}
];
app.get('/sses', function(req, res) {
res.set({
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
// 及時發(fā)送刷新響應(yīng)頭
res.flushHeaders();
setInterval(() => {
const data = {
message: `Current time is ${new Date().toLocaleTimeString()}`
};
res.write(`data: ${JSON.stringify(data)}\n\n`);
}, 3000);
});
}
module.exports = {List,Longstream}
可以直接食用。
描述:res.flushHeaders()
在Node.js中,res.flushHeaders()是一個用于手動刷新HTTP響應(yīng)頭的方法。它通常在需要立即發(fā)送響應(yīng)頭而不等待響應(yīng)體時使用。這在某些情況下是很有用的,比如在處理大文件下載或者流式傳輸時。
當Node.js收到HTTP請求時,它會自動為該請求創(chuàng)建一個響應(yīng)對象res,該對象具有一些屬性和方法,用于設(shè)置和發(fā)送HTTP響應(yīng)。res.flushHeaders()方法會立即發(fā)送HTTP響應(yīng)頭給客戶端,而不會等到整個響應(yīng)體準備好后再發(fā)送。這樣可以更快地向客戶端發(fā)送響應(yīng)頭,并讓客戶端更早地知道響應(yīng)的內(nèi)容類型、長度等信息。
以下是一個使用res.flushHeaders()方法的示例,該示例通過流式傳輸發(fā)送一個大文件
const http = require('http');
const fs = require('fs');
http.createServer(function(req, res) {
res.writeHead(200, {
'Content-Type': 'application/octet-stream',
'Content-Disposition': 'attachment; filename=largefile.dat'
});
const stream = fs.createReadStream('/path/to/largefile.dat');
stream.pipe(res);
// 刷新響應(yīng)頭
res.flushHeaders();
}).listen(8080);
在上面的示例中,我們使用createReadStream()方法創(chuàng)建了一個可讀流,并將其通過管道pipe()方法連接到res響應(yīng)對象。在開始傳輸文件之前,我們調(diào)用了res.writeHead()方法設(shè)置了HTTP響應(yīng)頭,并在傳輸過程中調(diào)用res.flushHeaders()方法立即發(fā)送了HTTP響應(yīng)頭給客戶端。這樣,客戶端就可以更快地知道文件類型和大小等信息,并開始下載文件。
更詳細的就可以參考:SSE描述
原生的sse貌似不支持修改請求頭
缺點:不可以比如請求頭中加token等
Server-Sent Events(以下簡稱 SSE)及event-source-polyfill使用單向長連接(后臺主動向前端推送)文章來源:http://www.zghlxwxcb.cn/news/detail-484233.html
import {EventSourcePolyfill} from 'event-source-polyfill';
let base = process.env.VUE_APP_SYSTEMURL;
let url = `${base}/server/sampleRemovePush/sse`;
let { access_token } = this.$store.state.login.login;
var es = new EventSourcePolyfill(url, {
headers: {
Authorization: access_token ? `Bearer${access_token}` : ""
}
});
es.onopen = function(event) {
console.log("連接成功", event);
};
es.onmessage = function(event) {
// to to something…
console.log("接收信息", event);
};
es.onerror = function(error) {
// 監(jiān)聽錯誤
console.log("錯誤", error);
};
文章來源地址http://www.zghlxwxcb.cn/news/detail-484233.html
到了這里,關(guān)于WEB通訊技術(shù)。前端實現(xiàn)SSE長連接,nodejs+express搭建簡單服務(wù)器,進行接口調(diào)試,通過curl請求數(shù)據(jù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!