瀏覽器如何定位一台服務器?
使用url統一資源定位符:protocal://hostname:port/path?query#hash
- protocal: 協議,服務器根據不同的協議確定數據交換的格式和方式,常用的有
http和https; -
hostname: 主機名,可以是ip,也可以是域名;
- ip:網絡中每個終端的唯一編號;
- 域名:和ip一一對應,方便記憶;
- 域名和ip的關係:計算機是通過ip在網絡上查找的另一台計算機,域名是方便人閲讀和記憶。輸入域名的時候,計算機會先去通過域名解析服務器(DNS)將域名轉化成ip,再去網絡中根據這個ip查找計算機。
-
port:端口號,服務器中有很多其它的應用,端口是用來定位使用服務器中的哪一個應用;
- http: 默認端口
80 - https:默認端口
443
- http: 默認端口
- path:路徑,用於區分使用web服務器的哪個服務。
-
query:查詢參數,用於向web服務器傳遞信息。
url只支持ASCII字符,輸入中文會被轉義
- hash:錨點,定位頁面中的內容,唯一一個改變後瀏覽器不會重新訪問服務器的值(不會刷新頁面),可以用來做路由。
瀏覽器和服務器傳輸數據的格式是什麼?
http是其中一種用來規定瀏覽器和服務器傳輸數據格式的協議。
http將瀏覽器和服務器之間的一次交互分為兩個部分:
- 請求request:客户端發生數據給服務器的過程
- 響應response:服務器收到請求返回一個數據給客户端的過程
其實一個請求可以看做是一個規定了格式的特殊字符串,下面我們看看這個字符串是有什麼組成的。
以百度的網址為例,
請求request由請求頭和請求體兩個部分組成:
1. 請求頭(request headers)
規定請求的請求方式,就是告訴服務器自己給什麼格式的數據,以什麼方式給,希望返回什麼數據等。
GET /s?wd=abc HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: PSTM=1563287690;
請求頭又包括請求行和其它屬性:
-
請求行:請求頭的第一行
- 請求方法:GET、POST等
- path:url中的path + search + has
- 協議及版本號:HTTP/1.1
-
其它屬性:後面的數據以鍵值對的形式存儲,可以自定義
- Host: 主機名
- Connection: 連接方式
2. 請求體(request body)
- 請求體就是瀏覽器要發送給服務器的數據,一般是服務器需要用到的業務數據。
-
請求頭中也可以傳遞不同格式的數據,一般由請求頭中的
Content-Type屬性來描述請求體中使用的格式。-
常見的格式:
application/x-www.form-urlencoded對應的數據格式:屬性名=屬性值&屬性名=屬性值application/json對應的數據格式:{"屬性名":"屬性值", "屬性名":"屬性值"}multipart/form-data對應的數據格式:使用某個隨機字符串作為屬性之間的分隔符,通常用於文件上傳。
------WebKitFormBoundaryD1o3TzulmXAIABD2 Content-Disposition: form-data; name="image"; filename="xxx.png" Content-Type: image/png ------WebKitFormBoundaryD1o3TzulmXAIABD2--
-
響應response由響應頭和響應體兩個部分組成:
1. 響應頭(response headers)
服務器根據請求頭和請求體構建出來的數據,告訴客户端響應的狀態,響應數據的格式等信息。
HTTP/1.1 200 OK
Content-Length: 24
Content-Type: text/plain; charset=UTF-8
Date: Mon, 03 Feb 2020 10:21:37 GMT
響應頭又包括響應行和其它屬性:
-
請求行:請求頭的第一行
- 協議及版本號:HTTP/1.1
- 狀態碼:對應不同的響應狀態
- 狀態文本:用於描述狀態碼的文本
常見的狀態碼:
200: 請求成功。
301:資源永久重定向,告訴瀏覽器這個資源已經不在當前地址了,去其它地方取,其它地方的地址一般放在Location屬性中。
302:資源臨時重定向,告訴瀏覽器這個資源沒有變化,自己去緩存中拿。
400:請求有問題,當前請求服務器無法識別。
403:服務器拒絕執行,可能是權限不夠造成的,服務器不返回數據。
404:頁面找不到,告訴瀏覽器這個地址不對,我這裏找不到對應的資源。
500:服務器內部錯誤,表示是服務器處理程序出錯。
502:網關錯誤,瀏覽器請求的地址可能還會進行一層網關的過濾,用來分發到不同的服務器,網關錯誤表示代理網關無法從上游服務器獲取數據。
503:服務器過載,表示當前服務器處理不了那麼多請求,拒絕當前瀏覽器發出的請求,一般會在響應頭添加一個Retry-After屬性。
504:網關超時,網關請求上游服務器一般會設置的一個時間限制,在規定時間內沒有從上游服務器獲取數據就會產生該錯誤信息。
-
其它屬性:後面的數據以鍵值對的形式存儲,可以自定義
- Server: web服務器類型,Apache、IIS等
- Content-Type: 描述響應體中的數據格式
2. 響應體(response body)
服務器返回給客户端的業務數據
常見的數據格式有:
text/plain:普通的存文本。瀏覽器會原封不動的顯示在頁面上。text/html:html文檔,瀏覽器會將返回的數據解析成頁面。text/css:css代碼,瀏覽器會根據返回數據渲染html頁面。text/javascript:js代碼,瀏覽器會啓動js引擎進行解析。attachment:附件、瀏覽器看到該屬性會自動下載服務器返回的數據。- 其它MIME類型
POST請求和GET請求的區別?
就協議的角度來講是沒有什麼實質的區別,不管是那種請求都是由請求頭和請求體組成的,只不過服務器會根據請求的方式不同去不同的地方讀取業務數據。
服務器對於不同的請求方法做出的處理(不是絕對的,開發者可以自己處理)
- GET請求:服務器遇到GET請求一般會去path中讀取數據。
- POST請求:服務器遇到POST請求一般會去請求體中讀取數據。
瀏覽器對於不同請求做出的處理
- GET請求會限制url大小,因此如果業務數據過大要使用POST請求。
- POST請求只能通過表單的形式提交,在瀏覽器地址欄輸入的url都是以GET的方式向服務器發送請求。
其它差異:
- GET請求會保留請求數據,利於用户做分享。
- GET請求的業務數據是放在url中的,一般帶有用户信息的數據都不應該使用GET請求,防止被其它人偷窺,或者被用户自己分享出去。
什麼是Ajax?
AJAX = Asynchronous JavaScript and XML(異步的 JavaScript 和 XML)。
是瀏覽器提供給js的請求網絡數據的API。
請求實例:
var xhr = new XMLHttpRequest(); //創建請求實例
// 監聽請求變化的函數
xhr.onreadystatechange = function (response) {
if (xhr.readyState === 4 && xhr.status === 200) { //表示所有內容接受完畢,並且服務器返回的狀態是請求成功
console.log(xhr.responseText);
}
}
xhr.open("GET", "https://api.binstd.com/shouji/query"); //配置請求
xhr.send(); //構建請求體,發送請求體
現在大部分的請求都使用fetch替代ajax。(fetch是es6提供的請求網絡數據的新API,用promise封裝的網絡請求API。)
什麼是跨域?
- 協議,域名,端口三者有一個不同就會造成跨域無法獲取數據的問題;
- 跨域是瀏覽器為了提高安全性做的限制。只有在瀏覽器中才會發生的現象。服務器之間互相訪問是不會出現跨域問題的;
link、img、script等含有src屬性的標籤也不會出現跨域問題;- 解決跨域問題,有jsonp,後台設置運行跨域,iframe等方法;但是副作用最少,無需後台配合的就是自己寫代理服務器。
代理服務器
服務器代理解決跨域問題思路:
- 出現跨域問題一般是請求不同域下的資源,請求相同域中的資源不會出現跨域問題。
- 自己編寫一個服務器,將要發請求的頁面放在該服務器下,再通過自己的服務器請求真實接口,將返回的數據回傳給頁面就可以解決跨域問題。
代理服務器的作用:你請求有跨域問題,我請求不會,我幫你請求再把數據返回給你。
舉個例子:
環境:node v10.16.0,yarn 1.15.2
目錄結構:
- demo.html
- proxy.js
-
在項目根目錄打開
cmd,運行命令:yarn init yarn add express yarn add request -
新建
demo.html文件,代碼如下:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>測試跨域請求</title> </head> <body> <script> var xhr = new XMLHttpRequest(); //創建請求實例 // 監聽請求變化的函數 xhr.onreadystatechange = function (response) { if (xhr.readyState === 4 && xhr.status === 200) { //表示所有內容接受完畢,並且服務器返回的狀態是請求成功 console.log(JSON.parse(xhr.responseText)); } } xhr.open("GET", "http://localhost:2020/api"); //配置請求 xhr.send(); //構建請求體,發送請求體 </script> </body> </html> -
新建
proxy.js文件,代碼如下:var express = require('express'); //導入express模塊 var request = require('request'); //導入request模塊 var app = new express(); //創建express實例 app.use(express.static('./')); //監聽文件夾,獲取靜態資源 app.listen(2020); //監聽2020端口 //監聽api接口 app.get('/api', function (req, res) { // 請求真實接口 request('https://api.binstd.com/shouji/query', function(error,response,body){ res.header('Content-Type', 'application/json;charset=utf-8'); res.send(body); //返回數據 }) }) - 啓動服務器,在
cmd輸入node proxy.js。 - 打開瀏覽器,輸入網址:
http://localhost:2020/demo.html,查看控制枱,現在就不會有跨域問題產生。
什麼是三次握手?
客户端與服務器建立TCP/IP連接的準備階段進行的三次交互被稱為三次握手。
http協議是基於TCP/IP協議建立的數據傳輸協議,http定義的是數據收發雙發的格式,TCP/IP協議定義的是數據接收時連接怎麼建立。
過程:
- 客户端向服務器發送請求;
- 服務器接收請求,向客户端發送迴應;
- 客户端接收回應;
為什麼要進行三次握手?
為了建立一個可靠的連接,確保客户端和服務器都具備收發能力。
分析:
假設只進行步驟1,客户端向服務器發送請求,客户端無法知道服務器真的能接到消息;
假設進行了步驟1,2,客户端知道服務器具備收數據的功能,服務器也知道客户端具備發數據的功能,但是服務器還不能確定客户端是否能收到數據;
所以要執行步驟3,這就是為什麼一定要三次握手。
什麼是四次揮手?
四次揮手是TCP/IP連接斷開時候客户端和服務器進行的四次交互過程。
過程:
- 客户端發送中斷請求,不再發送數據;
- 服務器接收中斷請求,數據沒發送完成,還可以發送數據;
- 服務器發送關閉連接請求 ,不可發送數據;
- 客户端確定關閉連接。
發完了,知道發完了,收完了,知道收完了
為什麼要進行四次揮手?
為了確保在斷開連接之前客户端和服務器的交互數據已經收發完畢。
分析:
- 客户端告訴服務器我要斷開連接,不再發送數據;
- 服務器知道了客户端要斷開請求,但是還有數據要發個客户端,告訴客户端先等我的數據發完再斷開連接;
- 過了一會服務器數據發送完畢,服務器告訴客户端數據發完了,可以關閉連接了(此時服務端不再接收客户端消息);
- 客户端收到通知,關閉連接,不再接受服務端消息。完成整個斷開連接過程。