瀏覽器中的網絡請求
第一次寫於: 2020年3月29日
最近, 學習了一些網絡知識; 所以就想着結合實際用到的內容, 寫一篇文章;
ajax
我們使用HTTP協議用於和server端的數據交互;
其中最常用的方式就是 ajax
它的定義和好處無需多言; 網上很多, 不再贅述;
有很多文章講的都是框架之上的使用, 屏蔽了原生內容;
我就想着稍微地瞭解一些具體瀏覽器是怎麼操作的;
這裏給大家做一個分享;
ajax 其實是對 HTTP
協議的封裝;
它會發起一個HTTP請求, 在請求的狀態改變(readyState)時, 執行我們傳入的方法;
發起請求
ajax 在瀏覽器中通過內置的 XMLHttpRequest
來生成;
let httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState === XMLHttpRequest.DONE) {
// Everything is good, the response was received.
} else {
// Not ready yet.
}
};
// 請求方法 請求URL 是否異步
httpRequest.open('GET', 'http://www.example.org/some.file', true);
// 在send之前; open之後
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
httpRequest.send("name=value&anothername=" + encodeURIComponent('哈哈哈') + "&so=on");
我們可以看到代碼中的操作
- 打開一個請求 指定請求方法,請求URL,是否異步
- 設置請求頭 這一步需要在 在send之前,open之後
- 發送數據 數據可以是字符串也可以是二進制數據
請求參數編碼
GET
httpRequest.send("name=value&anothername=" + encodeURIComponent('哈哈哈') + "&so=on");
我們可以注意到這行代碼中 encodeURIComponent
方法;
我們應該對參數名和參數值進行編碼; 這樣可以避免一些參數傳遞時的問題;
我們爲啥要對參數進行編碼呢?
GET
請求方式中, 我們的參數都編碼到URL上了;- URL 中是不能出現中文和一些特殊符號的
- 我們需要傳入一些中文和特殊符號
我們可以想象一下, 如果沒有對參數編碼會有啥後果;
- 中文是肯定不能傳入了
- 如果value是
123&a=b
這種, 它會不會變成 123 和a=b
?
爲了避免這些編碼上不必要的麻煩; 我們因此會對參數名, 參數值進行編碼;
當然, 也有對應的解碼的方法 decodeURIComponent
let plainText = 'h&123=12'
let encodedText = encodeURIComponent(plainText)
let decodedText = decodeURIComponent(encodedText)
POST
當我們發送一個 POST
請求時, 我們需要設置一個請求header的 Content-Type
用於說明, 我們請求的數據是哪種格式的.
POST常見的提交數據的格式有
- application/x-www-form-urlencoded 效果和GET請求編碼一樣; 但是數據是放在請求體中的;
- multipart/form-data 用於傳輸大數據; 有 boundary 進行數據分割;
- application/json RESTful API 接口最常用的數據格式;
- text/xml xml
POST請求處理請求數據, 它是把數據放在 請求體
中的;
但是, 這不代表POST請求中URL就不能編碼了;
其實, 還是可以加入額外的參數的; 但是一般情況下, 還是遵守約定俗成的規範;
接受請求
之前, 提到了我們可以根據 readyState
來判斷這個請求的狀態;
那麼有哪些狀態呢?
- UNSENT 0 (uninitialized) or (request not initialized)
- OPENED 1 (loading) or (server connection established)
- HEADERS_RECEIVED 2 (loaded) or (request received)
- LOADING 3 (interactive) or (processing request)
- DONE 4 (complete) or (request finished and response is ready)
let httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState === XMLHttpRequest.DONE) {
// Everything is good, the response was received.
} else {
// Not ready yet.
}
if (httpRequest.status === 200) {
var response = JSON.parse(httpRequest.responseText);
// Perfect!
} else {
// There was a problem with the request.
// For example, the response may have a 404 (Not Found)
// or 500 (Internal Server Error) response code.
}
};
接下來我們運行一下代碼試試;
如果我們直接在文件夾中打開html文件;
那麼, 我們會在地址欄中出現類似下面的情況
file:///C:/Users/ju/Desktop/ajax/test.html
這種情況下, 我們發送不了數據的;
打開devTool 我們會看到下面的報錯信息
Access to XMLHttpRequest at ‘http://www.example.org/some.file’ from origin ‘null’ has been blocked by
CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
這就是著名的瀏覽器跨域請求問題;
解決 跨域
有很多方法;
跨域
跨域
是因爲瀏覽器的同源策略導致的;
-
爲啥要有跨域呢?
-
爲啥瀏覽器要這麼做呢?
-
跨域提供了最基礎的安全;
-
防止別人惡意的請求;
默認情況下,JavaScript在發送 ajax 請求時,URL的域名端口號必須和當前頁面完全一致。
否則, 就會報跨域的異常;
那麼常見的解決方案有啥啊?
- JSONP 但是現在用的少了; 利用了瀏覽器中 一些標籤沒有跨域限制;
- NGINX 代理; 做一個靜態資源文件的代理;
- 後端修改請求頭, 設置
Access-Control-Allow-Origin
等 開發時
利用webpack-dev-server
(內部是用的http-proxy-middleware)
websocket
websocket 最近纔剛剛接觸;
只是做了一個小小的demo;
這裏就不敢胡謅了; 簡單談一些;
爲什麼要有 websocket
首先要知道, 瀏覽器是主動發送請求給服務器的;
但是, 反過來, 服務器是不能主動給瀏覽器發送請求的;
那麼, 在沒有 websocket
之前, 我們處理 瀏覽器和服務器之間的通信;
只能採用 輪詢
的方式;
所謂 輪詢
就是每個一段時間訪問一下服務器;
看看有沒有啥新的消息;
例如在線聊天: 每個client 都發送給server消息;
但是呢, server接受到消息之後, 並不能直接把消息返給其它client;
而只能等client 輪詢的時間到了, 再去把消息返回;
那麼, 面對用戶比較多, 而且對數據的實時性要求比較高;
例如, 視頻會議等; 那麼輪詢就顯得不行了;
websocket 有啥好處
websocket的出現, 就是解決了這一部分問題;
websocket 是利用 TCP
連接, 建立之後, 可以保持長時間的聯繫;
減少了多次請求;
var ws = new WebSocket("wss://echo.websocket.org");
ws.onopen = function(evt) {
console.log("Connection open ...");
ws.send("Hello WebSockets!");
};
ws.onmessage = function(evt) {
console.log("Received Message: " + evt.data);
ws.close();
};
ws.onclose = function(evt) {
console.log("Connection closed.");
};
和 XMLHttpRequest
代碼類似;
不過 onmessage
中可以多次觸發;
因爲, 近期學習了Rails, 使用了 Action Cable
, 提供的npm包進行的
客戶端與服務端的交互; 這裏就不展開說了;
推薦大家看一下 阮一峯websocket
有簡單明瞭的介紹;
之後, 隨着工作的接觸, 希望能對websocket有更多的瞭解;