HTML5中的webSocket、ajax、http
本文原鏈接:https://cloud.tencent.com/developer/article/1115496
https://cloud.tencent.com/developer/article/1193011
webSocket與ajax、web
- 一、webSocket與ajax
- 1、ajax
- 2、webSocket
- 二、webSocket API
- 1、事件
- 2、方法
- 3、屬性
- 4、常量
- 三、webSocket與HTTP
- 四、webSocket原理
- 五、webSocket的作用
- 1、ajax輪詢:
- 2、long poll
- 3、webSocket
- 六、Socket.io
先看一個(gè)有道釋義:
其實(shí)釋義的挺形象的,下面我來一一解釋哈:
1、聊天室:webSocket有名的應(yīng)用就是聊天室了;
2、服務(wù):webSocket提供客戶端請(qǐng)求的服務(wù)器和服務(wù);
3、套接字:源IP地址和目的IP地址以及源端口號(hào)和目的端口號(hào)的組合叫套接字,webSocket就是服務(wù)端和客戶端的結(jié)合;
4、協(xié)議:webSocket是基于TCP的一種新的網(wǎng)絡(luò)協(xié)議。
一、webSocket與ajax
作為一個(gè)碼了還算久代碼的前端,說起webSocket,腦子里最先閃現(xiàn)的當(dāng)然就是ajax ajax ajax......ajax是啥,ajax剛出來時(shí),可謂轟動(dòng)一時(shí),讓我們愉快地告別那種提交一個(gè)表單必須得填完所有信息,然后再把數(shù)據(jù)轉(zhuǎn)給服務(wù)器驗(yàn)證,結(jié)果發(fā)現(xiàn)有一個(gè)小小的輸入框里輸錯(cuò)了信息,然后又改掉重新提交走著重復(fù)的路的痛苦時(shí)代,所以它最大的貢獻(xiàn)就是局部刷新。當(dāng)然,不是說有了webSocket,它就out了,ajax現(xiàn)在依舊好用。下面稍微比較了下ajax和webSocket:
1、ajax
(1)瀏覽器主動(dòng)發(fā)送消息給服務(wù)器;
(2)非實(shí)時(shí)數(shù)據(jù)交互(異步,局部刷新)。
原生寫法:
四部曲:ajax對(duì)象、建立連接、發(fā)送請(qǐng)求、獲取相應(yīng)。
更通俗的用打電話來比喻,那就是:電話、撥號(hào)、說話、聽到對(duì)方回應(yīng)。demo
//創(chuàng)建一個(gè)ajax對(duì)象(想打電話,首先得有電話這個(gè)對(duì)象)var XHR = null; if (window.XMLHttpRequest) { // 非IE內(nèi)核 XHR = new XMLHttpRequest(); } else if (window.ActiveXObject) { // IE內(nèi)核,早期IE的版本寫法不同 XHR = new ActiveXObject("Microsoft.XMLHTTP"); } else { XHR = null; }
if(XHR){ //建立連接(撥號(hào)) XHR.open("GET", "ajaxServer.action",true); //發(fā)送請(qǐng)求(說話) XHR.send(); //獲取響應(yīng)(聽到對(duì)方回應(yīng)) XHR.onreadystatechange = function () { // readyState值說明 // 0,初始化,XHR對(duì)象已經(jīng)創(chuàng)建,還未執(zhí)行open // 1,載入,已經(jīng)調(diào)用open方法,但是還沒發(fā)送請(qǐng)求 // 2,載入完成,請(qǐng)求已經(jīng)發(fā)送完成 // 3,交互,可以接收到部分?jǐn)?shù)據(jù)
// 4,交互完畢 // status值說明 // 200:成功 // 404:沒有發(fā)現(xiàn)文件、查詢或URl // 500:服務(wù)器產(chǎn)生內(nèi)部錯(cuò)誤 if (XHR.readyState == 4 && XHR.status == 200) { // 這里可以對(duì)返回的內(nèi)容做處理 // 一般會(huì)返回JSON或XML數(shù)據(jù)格式 console.log(XHR.responseText); // 主動(dòng)釋放,JS本身也會(huì)回收的 XHR = null; } }; }
JQuery寫法(so easy,媽媽再也不用擔(dān)心我的學(xué)習(xí)啦):
$.ajax({type:"post", url:url, async:true, data:params, dataType:"json", success:function(res){ console.log(res); }, error:function(jqXHQ){ alert("發(fā)生錯(cuò)誤:"+jqXHQ.status); } });?
2、webSocket
(1)實(shí)現(xiàn)了瀏覽器與服務(wù)器全雙工(full-duplex)通信——允許服務(wù)器主動(dòng)發(fā)送信息給客戶端;
(2)實(shí)時(shí)數(shù)據(jù)交互。
WebSocket 握手過程
WebSocket 協(xié)議本質(zhì)上是一個(gè)基于 TCP 的協(xié)議,WebSocket
連接與 TCP 連接的建立過程類似[4]。但與傳統(tǒng)的基于 TCP 連 接的協(xié)議有所不同的是 WebSocket 協(xié)議需要從 HTTP 協(xié)議“過 渡”而來,而這個(gè)“過度”過程也被稱為 WebSocket 協(xié)議的握手 過程。因此想要建立基于 WebSocket 的 Web 應(yīng)用必須首先了解 WebSocket 協(xié)議的握手機(jī)制,如圖 2 給出了 WebSocket 協(xié)議握手 過程的示意圖。
首先由瀏覽器客戶端向服務(wù)器發(fā)起 WebSocket 握手請(qǐng)求報(bào) 文,這個(gè)報(bào)文是基于 HTTP 協(xié)議的,它告訴服務(wù)器客戶端想要升 級(jí)當(dāng)前的 HTTP 協(xié)議為 WebSocket 協(xié)議。服務(wù)器收到客戶端的 WebSocket 握手請(qǐng)求報(bào)文之后會(huì)對(duì)報(bào)頭進(jìn)行解析,如果服務(wù)器 理解客戶端握手請(qǐng)求報(bào)頭并且滿足升級(jí)為 WebSocket 協(xié)議的條 件,便會(huì)向客戶端發(fā)送握手應(yīng)答報(bào)文,這個(gè)應(yīng)答報(bào)文同樣是基于 HTTP 協(xié)議的。客戶端收到服務(wù)器的應(yīng)答報(bào)文后會(huì)對(duì)該報(bào)文進(jìn) 行一次驗(yàn)證,驗(yàn)證成功之后便會(huì)成功升級(jí)為 WebSocket 協(xié)議,如 果驗(yàn)證失敗客戶端將會(huì)主動(dòng)斷開連接。建立了 WebSocket 連接 之后,雙方便可以進(jìn)行全雙工通信,?
WebSocket 握手過程與 TCP 握手過程類似,但是 WebSocket 協(xié)議握手采用了更加簡(jiǎn)潔的方式。
相對(duì)于傳統(tǒng)的 TCP 握手,WebSocket 握手協(xié)議有以下明顯 的特點(diǎn): 首先,WebSocket 整個(gè)握手過程只需要兩次握手,相對(duì) 于 TCP 的三次握手,WebSocket 簡(jiǎn)化并且加入了自己的規(guī)則。 其次,WebSocket 握手協(xié)議是基于 HTTP 協(xié)議的,相對(duì)于字節(jié)流 的解析,ASCII 序列解析起來更加簡(jiǎn)便。最后,WebSocket 握手 協(xié)議引入了隨機(jī)序列認(rèn)證機(jī)制,易于實(shí)現(xiàn)。
兩次握手成功預(yù)示著雙方接下來將升級(jí)當(dāng)前的 HTTP 協(xié)議 為 WebSocket 協(xié)議。WebSocket 握手請(qǐng)求報(bào)文的報(bào)頭部分除了 必須包含必要的 HTTP 字段[5],還須遵循通用消息格式[RFC 822],同時(shí)又要包含和 WebSocket 緊密聯(lián)系的字段[6],如 Web- Socket 協(xié)議的版本信息、客戶端隨即生成的 Key、必要的 GET 請(qǐng) 求方法等。?
?
// Create WebSocket connection. var socket = new WebSocket('ws://localhost:8080'); //創(chuàng)建一個(gè)webSocket實(shí)例 // Connection opened socket.addEventListener('open', function (event) { //一旦服務(wù)端響應(yīng)WebSocket連接請(qǐng)求,就會(huì)觸發(fā)open事件 socket.send('Hello Server!'); }); // Listen for messages socket.addEventListener('message', function (event) { //當(dāng)消息被接受會(huì)觸發(fā)消息事件 console.log('Message from server', event.data); });?
二、webSocket API
既然上面寫了一部分代碼,那不如把API全都貼出來,哈哈哈。
首先,創(chuàng)建一個(gè)webSocket實(shí)例:
var socket = new WebSocket('ws://localhost:8080');然后再看下面的的API。
1、事件
(1)open
一個(gè)用于連接打開事件的事件監(jiān)聽器。當(dāng)readyState的值變?yōu)?OPEN 的時(shí)候會(huì)觸發(fā)該事件。該事件表明這個(gè)連接已經(jīng)準(zhǔn)備好接受和發(fā)送數(shù)據(jù)。這個(gè)監(jiān)聽器會(huì)接受一個(gè)名為"open"的事件對(duì)象。
socket.onopen = function(e) { console.log("Connection open..."); };或者:
socket.addEventListener('open', function (event) { console.log("Connection open..."); });(2)message
一個(gè)用于消息事件的事件監(jiān)聽器,這一事件當(dāng)有消息到達(dá)的時(shí)候該事件會(huì)觸發(fā)。這個(gè)Listener會(huì)被傳入一個(gè)名為"message"的?MessageEvent?對(duì)象。
socket.onmessage = function(e) { console.log("message received", e, e.data); };(3)error
當(dāng)錯(cuò)誤發(fā)生時(shí)用于監(jiān)聽error事件的事件監(jiān)聽器。會(huì)接受一個(gè)名為“error”的event對(duì)象。
socket.onerror = function(e) { console.log("WebSocket Error: " , e); };(4)close
用于監(jiān)聽連接關(guān)閉事件監(jiān)聽器。當(dāng) WebSocket 對(duì)象的readyState 狀態(tài)變?yōu)?CLOSED 時(shí)會(huì)觸發(fā)該事件。這個(gè)監(jiān)聽器會(huì)接收一個(gè)叫close的?CloseEvent?對(duì)象。
socket.onclose = function(e) { console.log("Connection closed", e); };2、方法
(1)send
通過WebSocket連接向服務(wù)器發(fā)送數(shù)據(jù)。
一旦在服務(wù)端和客戶端建立了全雙工的雙向連接,可以使用send方法去發(fā)送消息,當(dāng)連接是open的時(shí)候send()方法傳送數(shù)據(jù),當(dāng)連接關(guān)閉或獲取不到的時(shí)候回拋出異常。
一個(gè)通常的錯(cuò)誤是人們喜歡在連接open之前發(fā)送消息。如下所示:
// 這將不會(huì)工作 var socket= new WebSocket("ws://localhost:8080") socket.send("Initial data");應(yīng)該等待open事件觸發(fā)后再發(fā)送消息,正確的姿勢(shì)如下:
var socket= new WebSocket("ws://localhost:8080") socket.onopen = function(e) { socket.send("Initial data"); }(2)close
關(guān)閉WebSocket連接或停止正在進(jìn)行的連接請(qǐng)求。如果連接的狀態(tài)已經(jīng)是closed,這個(gè)方法不會(huì)有任何效果。
使用close方法來關(guān)閉連接,如果連接已經(jīng)關(guān)閉,這方法將什么也不做。調(diào)用close方法后,將不能再發(fā)送數(shù)據(jù)。close方法可以傳入兩個(gè)可選的參數(shù),code(numerical)和reason(string),以告訴服務(wù)端為什么終止連接。
socket.close(1000, "Closing normally"); //1000是狀態(tài)碼,代表正常結(jié)束。?
3、屬性
| binaryType | DOMString | 一個(gè)字符串表示被傳輸二進(jìn)制的內(nèi)容的類型。取值應(yīng)當(dāng)是"blob"或者"arraybuffer"。 "blob"表示使用DOMBlob?對(duì)象,而"arraybuffer"表示使用?ArrayBuffer?對(duì)象。 |
| bufferedAmount | unsigned long | 調(diào)用?send()?方法將多字節(jié)數(shù)據(jù)加入到隊(duì)列中等待傳輸,但是還未發(fā)出。該值會(huì)在所有隊(duì)列數(shù)據(jù)被發(fā)送后重置為 0。而當(dāng)連接關(guān)閉時(shí)不會(huì)設(shè)為0。如果持續(xù)調(diào)用send(),這個(gè)值會(huì)持續(xù)增長(zhǎng)。只讀。 |
| extensions | DOMString | 服務(wù)器選定的擴(kuò)展。目前這個(gè)屬性只是一個(gè)空字符串,或者是一個(gè)包含所有擴(kuò)展的列表。 |
| protocol | DOMString | 一個(gè)表明服務(wù)器選定的子協(xié)議名字的字符串。這個(gè)屬性的取值會(huì)被取值為構(gòu)造器傳入的protocols參數(shù)。 |
| readyState | unsigned short | 連接的當(dāng)前狀態(tài)。取值是?Ready state constants之一。只讀。 |
| url | DOMString | 傳入構(gòu)造器的URL。它必須是一個(gè)絕對(duì)地址的URL。只讀。 |
4、常量
Ready state 常量
| CONNECTING | 0 | 連接還沒開啟。 |
| OPEN | 1 | 連接已開啟并準(zhǔn)備好進(jìn)行通信。 |
| CLOSING | 2 | 連接正在關(guān)閉的過程中。 |
| CLOSED | 3 | 連接已經(jīng)關(guān)閉,或者連接無法建立。 |
三、webSocket與HTTP
webSocket和http同為協(xié)議,大家心里肯定會(huì)想它倆之間有什么聯(lián)系,當(dāng)然,我也好奇,所以就有了下面的研究結(jié)果,呵呵呵呵~~
大家都知道,webSocket是H5的一種新協(xié)議(這樣看來和http是沒什么關(guān)系),本質(zhì)是通過http/https協(xié)議進(jìn)行握手后創(chuàng)建一個(gè)用于交換數(shù)據(jù)的TCP連接,服務(wù)端與客戶端通過此TCP連接進(jìn)行實(shí)時(shí)通信。也就是說,webSocket是http協(xié)議上的一種補(bǔ)充。
相對(duì)于HTTP這種非持久的協(xié)議來說,Websocket是一個(gè)持久化的協(xié)議。
以php的生命周期為例:
在http1.0中,一個(gè)request,一個(gè)response,一個(gè)周期就結(jié)束了。
在http1.1中,有了keep-alive,可以發(fā)送多個(gè)Request,接收多個(gè)Response。但在http中永遠(yuǎn)是一個(gè)request對(duì)應(yīng)一個(gè)response。而且這個(gè)response是被動(dòng)的,不能主動(dòng)發(fā)起。
這時(shí)候webSocket就派上用場(chǎng)了。
四、webSocket原理
首先,先來看一張http的Request Headers:
再看一張webSocket的:
以及webSocket的Response Headers:
I guess,無論熟不熟悉http,想必都看出了區(qū)別,哈哈哈。接下來就要對(duì)這些東西進(jìn)行講解啦:
(1)Upgrade和Connection
Upgrade: websocket Connection: Upgrade這個(gè)就是webSocket的核心,告訴Apache、ngix等服務(wù)器:注意啦,我發(fā)起的是webSocket協(xié)議,快點(diǎn)幫我找到對(duì)應(yīng)的助理處理~ 不是那個(gè)老土的http。
(2)Sec-WebSocket-Key、Sec-WebSocket-Extensions和Sec-WebSocket-Version
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Extensions: chat, superchat Sec-WebSocket-Version: 13這個(gè)很好理解啦,首先,Sec-WebSocket-Key是一個(gè)Base64 encode的值,這個(gè)是瀏覽器隨機(jī)生成的,告訴服務(wù)器:尼好,我是webSocket,這是我的ID卡,讓我過去吧。
然后,Sec-WebSocket-Extensions:協(xié)議擴(kuò)展, 某類協(xié)議可能支持多個(gè)擴(kuò)展,通過它可以實(shí)現(xiàn)協(xié)議增強(qiáng)
最后,Sec-WebSocket-Version是告訴服務(wù)器所使用的webSocket Draft(協(xié)議版本)。喏,我是小喵4.1版本哆啦A夢(mèng),哈哈哈哈哈哈哈哈。
然后只要服務(wù)器返回了上面我放的那一系列balabala的東西,就代表已經(jīng)接受請(qǐng)求,webSocket建立成功啦!
(3)Sec-WebSocket-Accept和Sec-WebSocket-Extensions
請(qǐng)求時(shí),webSocket會(huì)自帶加密過的ID卡過來讓服務(wù)端驗(yàn)證;
對(duì)應(yīng)的,接受請(qǐng)求之后,服務(wù)端也得搞一個(gè)安全卡(Accept頭域的值就是Key的值,是由瀏覽器發(fā)過來的Sec-WebSocket-Key生成的)來證明是我同意你通過的,而不是什么肯蒙拐騙的壞銀->
就這樣,原理部分就說完啦,握手成功!
五、webSocket的作用
說webSocket之前,先說一下ajax輪詢和long poll。
1、ajax輪詢:
ajax輪詢很簡(jiǎn)單,就是讓瀏覽器隔個(gè)幾秒就發(fā)送一次請(qǐng)求,詢問服務(wù)器是否有新信息。
客戶端:hello hello,有沒有新信息(Request)服務(wù)端:沒有(Response)客戶端:hello hello,有沒有新信息(Request) 服務(wù)端:沒有。。(Response) 客戶端:hello hello,有沒有新信息(Request) 服務(wù)端:你好煩啊,沒有啊。。(Response) 客戶端:hello hello,有沒有新消息(Request) 服務(wù)端:有啦有啦,here you are(Response) 客戶端:hello hello,有沒有新消息(Request) 服務(wù)端:。。沒。。。。沒。。。沒。。。。(Response)?
2、long poll
long poll和ajax輪詢?cè)砗芟?#xff0c;不過long poll是阻塞模型,簡(jiǎn)單來說,就是一直給你打電話,直到你接聽為止。
客戶端:hello hello,有沒有新信息,沒有的話就等有了再返回給我吧(Request)服務(wù)端:額。。。 (。。。。等待到有消息的時(shí)候。。。。) 有了,給你(Response)很明顯,ajax輪詢和long poll弊大于利:
(1)被動(dòng)性
上面這兩種方式都是客戶端先主動(dòng)消息給服務(wù)端,然后等待服務(wù)端應(yīng)答,要知道,等待總是難熬的,如果服務(wù)端能主動(dòng)發(fā)消息多好,這也就是缺點(diǎn)之一:被動(dòng)性。
(2)非常消耗資源
ajax輪詢 需要服務(wù)器有很快的處理速度和資源(速度);
long poll 需要有很高的并發(fā),也就是說同時(shí)接待客戶的能力(場(chǎng)地大小)。
so,當(dāng)ajax輪詢和long poll碰上503(啊啊啊啊啊,game over)
這時(shí)候,神奇的webSocket又派上用場(chǎng)了。
?
3、webSocket
(1)被動(dòng)性
首先,解決被動(dòng)性:
客戶端:hello hello,我要建立webSocket協(xié)議,擴(kuò)展服務(wù):chat,Websocket,協(xié)議版本:17(HTTP Request)服務(wù)端:ok,確認(rèn),已升級(jí)為webSocket協(xié)議(HTTP Protocols Switched)客戶端:麻煩你有信息的時(shí)候推送給我噢。。服務(wù)端:ok,有的時(shí)候會(huì)告訴你的。服務(wù)端:balabalabalabala服務(wù)端:balabalabalabala服務(wù)端:哈哈哈哈哈啊哈哈哈哈服務(wù)端:笑死我了哈哈哈哈哈哈哈就這樣,只需要一次http請(qǐng)求,就會(huì)有源源不斷的信息傳送了,是不是很方便。
(2)消耗資源問題
首先,了解一下,我們所用的程序是要經(jīng)過兩層代理的,即http協(xié)議在Nginx等服務(wù)器的解析下,然后再傳送給相應(yīng)的Handler(PHP等)來處理。簡(jiǎn)單地說,我們有一個(gè)非??焖俚慕泳€員(Nginx),他負(fù)責(zé)把問題轉(zhuǎn)交給相應(yīng)的客服(Handler)?。
本身接線員基本上速度是足夠的,但是每次都卡在客服(Handler)了,老有客服處理速度太慢,導(dǎo)致客服不夠。
webSocket就解決了這樣一個(gè)難題,建立后,可以直接跟接線員建立持久連接,有信息的時(shí)候客服想辦法通知接線員,然后接線員再統(tǒng)一轉(zhuǎn)交給客戶。
這樣就可以解決客服處理速度過慢的問題了。
同時(shí),在傳統(tǒng)的方式上,要不斷的建立,關(guān)閉HTTP協(xié)議,由于HTTP是非狀態(tài)性的,每次都要重新傳輸鑒別信息,來告訴服務(wù)端你是誰。
雖然接線員很快速,但是每次都要聽這么一堆,效率也會(huì)有所下降的,同時(shí)還得不斷把這些信息轉(zhuǎn)交給客服,不但浪費(fèi)客服的處理時(shí)間,而且還會(huì)在網(wǎng)路傳輸中消耗過多的流量/時(shí)間。
但是webSocket只需要一次http握手,所以說整個(gè)通訊過程是建立在一次連接/狀態(tài)中,也就避免了http的非狀態(tài)性,服務(wù)端會(huì)一直知道你的信息,直到你關(guān)閉請(qǐng)求,這樣就解決了接線員要反復(fù)解析http協(xié)議,還要查看identity info的信息。
六、Socket.io
既然說到了webSocket,就難免扯到socket.io。
有人說socket.io就是對(duì)webSocket的封裝,并且實(shí)現(xiàn)了webSocket的服務(wù)端代碼。可以這樣說,但不完全正確。
在webSocket沒有出現(xiàn)之前,實(shí)現(xiàn)與服務(wù)端的實(shí)時(shí)通訊可以通過輪詢來完成任務(wù)。Socket.io將webSocket和輪詢(Polling)機(jī)制以及其它的實(shí)時(shí)通信方式封裝成了通用的接口,并且在服務(wù)端實(shí)現(xiàn)了這些實(shí)時(shí)機(jī)制的相應(yīng)代碼。也就是說,webSocket僅僅是Socket.io實(shí)現(xiàn)實(shí)時(shí)通信的一個(gè)子集。
下面直接上一個(gè)用socket.io做的小小聊天室吧。
(1)首先你得有node,然后安裝socket.io。
$ npm install socket.io(2)服務(wù)器端(index.js)
'use strict'; module.exports = require('./lib/express'); var app = require('express')(); var http = require('http').Server(app); var io = require('socket.io')(http); app.get('/', function(req, res){ res.sendFile(__dirname + '/index.html'); }); io.on('connection', function(socket){ socket.on('message',function(msg){ console.log(msg); socket.broadcast.emit('chat',msg); //廣播消息 }) }); http.listen(3000);(3)客戶端
先引入js文件:
<script src="/socket.io/socket.io.js"></script>交互代碼(index.html):
<!DOCTYPE html><html><head> <meta charset="UTF-8"> <title>聊天室</title> <style> body,div,ul,li{margin: 0;padding: 0;list-style: none;} .auto{margin: auto;} .l{text-align: left;} .r{text-align: right;} .flex{display: box;display: -webkit-box;display: -moz-box;display: -ms-flexbox;display: -webkit-flex;display: flex;-webkit-box-pack: center;-webkit-justify-content: center;-moz-justify-content: center;-ms-justify-content: center;-o-justify-content: center;justify-content: center;-webkit-box-align: center;-webkit-align-items: center;-moz-align-items: center;-ms-align-items: center;-o-align-items: center;align-items: center;} .chat-box{background: #f1f1f1;width: 56vw;padding:2vw;height:36vw;border:1px solid #ccc;margin-top: 2vw;} .chat-li{display:inline-block;margin-top: 5px;background: #5CB85C;border-radius: 5px;padding: 3px 10px;color: #fff;} .other-chat-li{background: #fff;color: #333;} .send-box{width: 60vw;border:1px solid #ccc;justify-content: space-between;border-top: 0;} .send-text{width: 50vw; border: none; padding: 10px;outline:0;} .send{width: 10vw;background: #5cb85c; border: none; padding: 10px;color: #fff;cursor: pointer;} .chat-name{color: #f00;} .other-box,.self-box{width: 50%;height:100%;} </style> </head轉(zhuǎn)載于:https://www.cnblogs.com/leftJS/p/11041346.html
總結(jié)
以上是生活随笔為你收集整理的HTML5中的webSocket、ajax、http的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大班体育游戏教案《老鼠笼》
- 下一篇: 华为移动路由器怎么用 华为路由器如何使用