2020(春)前端面試知識點詳解

1.盒模型

盒模型是CSS的核心概念,描述了元素如何顯示,以及(在必定程度上)如何互相做用互相影響。頁面中全部的元素都被看做一個矩形盒子,這個盒子包含元素的內容、內邊距padding、邊框border和外邊距margincss

默認盒模型的width屬性應用給內容區
  • 經過修改box-sizing屬性能夠改變計算盒子大小的方式。box-sizing的默認值爲content-box,即默認盒模型的width屬性應用給內容區
  • 若是把box-sizing的值修改成border-box,那麼width和height屬性的值將會包含內邊距和邊框。此時,外邊距仍會影響盒子在頁面中佔據的總體空間,即它的寬度不會計算到width中。
  • 應用

默認狀況下,讓.group中的 .block寬度在任意狀況下都佔其父元素的1/3,可使用如下規則:html

.group .block{
    width:33.333%;
}

可是,若是給.block添加了內邊距,它的寬度就會變成.group元素的1/3外加應用給它的內邊距。若是這是三欄佈局,就會破壞。要解決這個問題,能夠再增長一個內部元素,而後改成爲這個元素添加內邊距,或者設置一個不一樣的box-sizing值,從而修改盒子寬度的計算方式:git

.group .block{
    width:33.333%;
    box-sizing:border-box;
    padding:20px;
}
//此時,不管是否添加內邊距,不管內邊距是多少,.block的寬度始終保持爲其父元素的1/3
CSS規定:上、下方位的內、外邊距(5%),仍然基於包含塊(父元素)的寬度來計算,某些狀況不必定

2.垂直水平居中

<body>
<div id="test">
</div>
</body>

第一種github

//最簡單,已知高寬
#test{
    width: 200px;
    height: 200px;
    background: pink;
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    margin: auto;
}
絕對定位盒模型的特性
left+right+margin+padding+width=包含塊的寬度
padding、margin默認爲0,設爲auto=包含塊寬-width

第二種web

//已知高寬
#test{
    width: 200px;
    height: 200px;
    background: deeppink;
    position: absolute;
    left: 50%;
    top: 50%;
    margin-left: -100px;
    margin-top: -100px;
    }

第三種算法

//已知或未知高寬
#test{
    width: 200px;
    height: 200px;
    background: red;
    position: absolute;
    left: 50%;
    top: 50%;//相對父
    //可用於已知
    //transform: translate(-100px,-100px);
    //未知元素水平垂直居中
    transform: translate(-50%,-50%);
   //相對自身,可用於未知高寬
  }

第四種json

//圖片垂直水平居中,可應用於未知高寬
<div id="test">
    <img src="img/玩具鴨.png">
</div>
html,body{
    height: 100%;
}
/*僞元素方法*/
#test{
    height: 100%;
    text-align: center;
}
img{
    vertical-align: middle;
}

#test:after{
    content: "";
    display: inline-block;
    height: 100%;
    width: 0px;
    vertical-align: middle;
}

第五種segmentfault

<body>
<div class="inner"></div>
</body>
/*felx方法*/
html,body{
    height: 100%;
    width: 100%;
}
body{
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100%;
}
.inner{
    width: 200px;
    height: 200px;
    background: red;
}

3.過渡/變形/動畫的屬性

在說動畫以前,先順便提一下過渡跨域

過渡


CSS transition提供了一種在更改CSS屬性的控制動畫速度的方法,其可讓屬性變化成爲一個持續一段時間的過程,而不是當即生效。
transition-property:默認值all,指定應用過渡的屬性名稱
transition-duration:以秒或毫秒爲單位指定過渡的時間(0s默認0s,必須帶單位),可指定多個時長分別對應多個屬性變化
transition-timing-function:給每一個屬性設置時間變化模式(屬性值有easylinearease-inease-out...)
transition-delay:延遲的時間瀏覽器

關於過渡的坑:
#test{
    transition-property:width;
    transition-duration:2s;
    transition-timing-function:liner;
}
body:hover #test{
    transition-property:height;
    width:200px;
    height:200px;
}
實際上:在鼠標移入body時候:width瞬間變化,height過渡;移除body時候:width過渡變回原型,height瞬間變回。
<script ...>
//transition元素首次渲染尚未結束狀況下,是不會被觸發的
    var test=document.querySelector("#test");
    test.style.width="300px"
</script>
並無觸發,在初始化時候,直接將width設置成爲300px
window.load=function(){
    var test=document.querySelector("#test");
    test.style.width="300px"
}
在頁面加載完成時觸發,transition有變化的過程
transition在頁面初試渲染完成後才觸發,變化的過程只展現在渲染之後
transition簡寫順序中,第一個時間解析爲transition-duration;第二個解析爲transition-delay
在絕大部分變換樣式的切換時,變換組合個數或位置不同時,是沒有辦法觸發過渡的

變形


2D變形:transform屬性容許修改CSS視覺格式模型的座標空間,transform屬性只對block級元素生效
平移:
transform:rotate(200dge)旋轉200度
transform:translateX(300px),向右平移300px,這裏須要思考CSS座標軸方向
transform:translateY(300px),向下平移300px
transform:translate(300px,300px),向右下平移
transform:translate(300px),單值只動X軸
斜切:
transform:skew(45deg)斜切
transform:skewX(45deg)沿X軸斜切
transform:skewY(45deg)沿Y軸斜切
transform:skew(45deg,45deg)斜切 O --> \
縮放:
transform:scale(1.5)1.5倍放大
transform:scaleX(n)X軸放大n倍
transform:scaleY(n)Y軸放大n倍
基點的變化:
transform-origin:left top按照左上角轉
transform-origin:50px 50px這裏轉

變換組合
順序是從右往左,變換的底層原理其實就是矩陣的運算

3D變形
perspective景深:讓3D場景有近大遠小效果,是一個不可繼承屬性但可做用於後代
應用景深的元素稱爲「舞臺元素」,舞臺元素的全部後代元素都會受影響(若是後代中也添加perspective屬性,效果疊加而不是覆蓋)
transform:perspective(1000px);默認是none,沿Z軸1000px,使用該元素須要放在transform的首位,放在其餘函數後面會被忽略
transform:rotate3d(Xdeg,Ydeg,Zdeg)
transform:translateZ(100px)
transform:translate3d(100px,100px,100px)
transform:scaleZ(n);沒有變化,須要和translateZ()配合使用,兩值相乘爲沿Z軸移動距離從而有擴大或縮小效果
transform:scale3d(n,n,n)
滅點:景深原理,控制滅點的位置,景深越大,滅點越遠,元素變形越小
perspective-origin:left top;控制視角的位置
transform-style:指定子元素如何在空間中展現,營造有層級的3D舞臺效果,不可繼承,做用於子元素
transform-style:flat(默認);全部子元素在2D平面呈現
transform-style:preserve-3d;全部元素在3D平面呈現
backface-visibility:hidden/visible;屬性用來設置是否顯示元素的背面,默認是顯示

動畫


animation-name指定應用的一系列動畫,每一個名稱表明一個由@keyforms定義的動畫序列
animation-duration指定一個動畫週期的時長,默認0s無動畫
animation-timing-function指定動畫快慢
animation-delay動畫開始前等待時間
animation-iteration-count動畫執行的次數
animation-direction動畫執行的方向(例如from-->to):normal/reverse
animation-fill-mode控制元素在動畫外的狀態
animation-fill-mode:backwards;from前狀態和from保持一致,to之後是本來
animation-fill-mode:forwards;to之後狀態和to保持一致,from之前是本來
animation-fill-mode:both;from前狀態和from保持一致,to之後狀態和to保持一致
animation-play-state:pause/running;定義動畫的運行和暫停

4.link 和 import 區別

<link href="./index.css" rel="stylesheet">

這段代碼告訴瀏覽器把index.css文件下載下來,而後把其中的樣式應用到網頁上。一樣的代碼能夠把這個樣式表應用到任意多個網頁上,所以這是一種跨網頁甚至跨網站重用樣式表的推薦方式。

<style type="text/css">
    @import url("./index.css");
<style>

能夠在HTML文檔的head部分把@import指令放在style中,也能夠在外部樣式表中使用它。後一種用法意味着,若是網頁加載外部樣式表,那麼瀏覽器後續可能還須要下載更多的CSS文件。

區別
1: Link屬於html標籤,而@import是CSS中提供的
2:在頁面加載的時候,link會同時被加載,而@import引用的CSS會在頁面加載完成後纔會加載引用的CSS
3:@import只有在ie5以上才能夠被識別,而link是html標籤,不存在瀏覽器兼容性問題
4:線上網頁最好把須要加載的CSS文件控制在1或者2個,若是用link元素加載CSS文件,而後又在其中使用@import,並不能把請求控制爲1個,由於這意味着現須要加載一個請求下載連接的文件,此外還要發送額外請求取得全部導入的文件

5.DOM解析和渲染 (CSS)

推薦閱讀
CSS加載不會阻塞DOM樹的解析,可是CSS加載會阻塞DOM樹的渲染,CSS加載會阻塞後面的js語句的執行

6.跨域(CORS)

CORS(Cross-Origin Resource Sharing,跨域資源共享)定義了在必須訪問跨源資源時,瀏覽器與服務器應該如何溝通。基本思想是使用自定義的HTTP頭部讓瀏覽器與服務器進行溝通,從而決定請求或響應是應該成功仍是應該失敗。
好比一個簡單的GET或POST請求,它沒有自定義的頭部,而主體內容是text/plain。在發送該請求時,須要給它附加一個額外的Origin頭部,其中包含請求頁面的源信息(協議、域名和端口),以便服務器根據這個頭部信息來決定是否給予響應。
Origin頭部的示例:
Origin:http://www.nczonline.net
若是服務器認爲這個請求能夠接受,就在Access-Control-Allow-Origin頭部中回發相同源信息(若是是公共資源,能夠回發「*」),例如:
Access-Control-Allow-Origin:http://www.nczonline.net
若是沒有這個頭部或者有這個頭部但源信息不匹配,瀏覽器就會駁回請求。正常狀況下,瀏覽器會處理請求。注意,請求和響應都不包含cookie信息。

IE對CORS的實現

IE8引入了XDR(XDomainRequest)類型。與XHR相似,XDR與XHR不一樣之處在於:

  • cookie不會隨着請求發出,也不會隨響應返回
  • 只能設置請求頭部信息中的Content-Type字段
  • 不能訪問響應頭部信息
  • 只支持GET和POST請求

這些變化使CSRF(Cross-Site Request Forgery,跨站點請求僞造)和XSS(Cross-Site Scripting,跨站點腳本)的問題獲得了緩解。被請求的資源能夠根據它認爲合適的任意數據(用戶代理、來源頁面等)來決定是否設置Access-Control-Allow-Origin頭部。做爲請求的一部分,Origin頭部的值表示請求的來源域,以便遠程資源明確地識別XDR請求。
XDR對象的使用方法與XHR對象很是相似。也是建立一個XDomainRequest的實例,調用open()方法,再調用send()方法。可是與XHR對象的open()方法不一樣,XDR對象的open()方法只接收兩個參數:請求的類型和URL。
全部的XDR請求都是異步執行的,不能用它來建立同步請求。請求返回以後,會觸發load事件,響應的數據也會保存在responseText屬性中,以下表示。
屏幕快照 2020-05-11 下午10.31.20.png
在接收到響應後,只能訪問響應的原始文本;沒有辦法確認響應的狀態代碼。並且,只要響應有效就會觸發load事件,若是失敗就會觸發error事件,除了錯誤自己以外,沒有其餘信息可用,所以惟一可以肯定的就只有請求未成功。要檢測錯誤,能夠指定一個onerror事件處理程序。
在請求返回前調用abort()方法能夠終止請求:

xdr.abort()://終止請求

也支持timeout屬性以及ontimeout事件處理程序
爲了支持POST請求,XDR對象提供了contentType屬性,用來表示發送數據的格式,這個屬性是經過XDR對象影響頭部信息的惟一方式
屏幕快照 2020-05-11 下午4.24.04.png

其餘瀏覽器對CORS的實現

Firefox3.5+、Safari4+、Chrome、IOS版Safari和Android平臺支持的WebKit都經過XMLHttpRequest對象實現了對CORS的原生支持。
在嘗試打開不一樣來源的資源時,無需額外編寫代碼就能夠觸發這個行爲。要求位於另外一個域中的資源,使用標準的XHR對象並在open()方法中傳入絕對的URL便可。

var xhr= new XMLHttpRequest()
xhr.onreadystatechange=function () {
    if (xhr.readyState==4){
        if ((xhr.status>=200 && xhr.status<300) || xhr.status==304){
            console.log(xhr.responseText)
        }else {
            console.log("request was unsuccessful:"+xhr.status)
        }
    }
}
xhr.open("get","https://developer.mozilla.org/en-US/docs/Web/API/XDomainRequest",true)
xhr.send(null);

打印頁面內容:
屏幕快照 2020-05-11 下午4.26.26.png
查看詳細內容
屏幕快照 2020-05-11 下午4.29.25.png
與 IE中的XDR對像不一樣,經過跨域XHR對象能夠訪問status和statusText屬性,並且還支持同步請求。跨域XHR對象也有一些限制,爲了安全這些限制是必需的:

  • 不能使用setRequestHeader()設置自定義頭部
  • 不能發送和接收cookie
  • 調用getAllResponseHeaders()方法總會返回空字符串

因爲不管同源請求仍是跨源請求都使用相同的接口,所以對於本地資源,最好使用相對URL,在訪問遠程資源時再使用絕對URL。這樣作能消除歧義,避免出現限制訪問頭部或本地cookie信息等問題。

Preflighted Requests(預檢請求)

CORS經過一種叫作Preflighted Requests的透明服務器驗證機制支持開發人員使用自定義的頭部、GET或POST以外的方法,以及不一樣類型的主體內容。在使用下列高級選項來發送請求時,就會像服務器發送一個Preflighted請求。這種請求使用OPTIONS方法,發送下列頭部。
Origin:與簡單的請求相同
Access-Control-Request-Method:請求自身使用的方法
Access-Control-Request-Header:(可選)自定義的頭部信息,多個頭部以逗號分隔
示例:一個帶有自定義頭部NCZ的使用POST方法發送的請求

Origin:http://www.nczonline.net
Access-Control-Request-Method:POST
Access-Control_Request-Headers:NCZ

發送這個請求後,服務器能夠決定是否容許這種類型的請求。服務器經過在響應中發送以下頭部與瀏覽器進行溝通。

Access-Control-Allow-Origin:與簡單的請求相同
Access-Control-Allow-Methods:容許的方法,多個方法以逗號分隔
Access-Control-Allow-Header:容許的頭部,多個頭部以逗號分隔
Access-Control-Max-Age:應該將這個Preflight請求緩存多長時間
示例:

Access-Control-Allow-Origin:http://www.nczonline.net
Access-Control-Allow-Methods:POST,GET
Access-Control-Allow-Header:NCZ
Access-Control-Max-Age:1728000

Preflight請求結束後,結果將按照響應中指定的時間緩存起來。而爲此付出的代價只是第一次發送這種請求時會多一次HTTP請求。支持Preflight請求的瀏覽器包括Firefox3.5+、Safari4+、Chrome。

帶憑據的請求

默認狀況下,跨源請求不提供憑據(cookie、HTTP認證及客戶端SSL證實等)。經過將withCredentials屬性設置爲true,能夠指定某個請求應該發送憑據。若是服務器接受帶憑據的請求,會用下面的HTTP頭部來響應。

Access-Control-Allow-Credentials:true

若是發送的事帶憑據的請求,但服務器的響應中沒有包含這個頭部,那麼瀏覽器就不會把響應交給JavaScript(因而,reponseText中將是空字符串,status的值爲0,並且會調用onerror()事件處理程序)。另外,服務器還能夠在Preflight響應中發送這個HTTP頭部,表示容許源發送帶憑據的請求。
支持withCredentials屬性的瀏覽器有Firefox3.5+、Safari4+、Chrome。

跨瀏覽器的CORS

即便瀏覽器對CORS的支持程度並不同,可是全部瀏覽器都支持簡單的(非Preflight和不帶憑據的)請求,所以有必要實現一個跨域瀏覽器的方案。檢測XHR是否支持CORS的最簡單方式,就是檢查是否存在withCredentials屬性。再結合檢測XDomianRequest對象是否存在,就能夠兼顧全部瀏覽器了。

function createCORSRequest(method,url) {
    var xhr=new XMLHttpRequest();
    if ('withCredentials' in xhr){
        xhr.open(method,url,true)
    }else if (typeof XDomainRequest != "undefined"){
        vxr = new XDomainRequest();
        xhr.open(method,url)
    }else {
        xhr=null;
    }
    return xhr
}
var request=createCORSRequest("get","https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise")
if(request){
    request.onload=function () {
        //對request.responseText進行處理
        console.log(request.responseText)
    }
    request.send()
}

Firefox、Safari和Chrome中的XMLHttpRequest對象與IE中的XDomainRequest對象相似,都提供了夠用的接口,所以以上模式仍是至關有用的。兩個對象共同的屬性/方法以下:

  • abort():用於中止正在進行的請求
  • onerror():用於替代onreadystatechange檢測錯誤
  • onload:用於替代onreadystatechange檢測成功
  • responseText:用於取得響應內容
  • send():用於發送求情

以上成員都包含在createCORSRequest()函數返回的對象中,在全部瀏覽器中都能正常使用。

圖像Ping

圖像Ping
一個網頁能夠從任何網頁中加載圖像,不用擔憂跨域不跨域。這也是在線廣告跟蹤瀏覽量的主要方式。動態的建立圖像,使用它們的onloadonerror事件處理程序來肯定是否接受到了響應。
動態建立圖像常常用於「圖像」Ping。圖像Ping是與服務器進行簡單、單向的跨域通訊的一種方式。請求的數據是經過查詢字符串形式發送的,而響應能夠是任意內容,但一般是像素或204響應。經過圖像Ping,瀏覽器得不到任何具體的數據,但經過監聽loaderror事件,它能知道響應是何時接受到的。以下例子:

var img=new Image()
Img.onload=img.onerror=function(){
    alert(「Done!」);
};
Img.src=「http://www.example.com/test?name=Nicholas」;

這裏建立了一個Image的實例,而後將onload和onerror事件處理程序指定爲同一個函數。這樣不管是什麼響應,只要請求完成,就能獲得通知。請求從設置src屬性那一刻開始,而這個例子在請求中發送了一個name參數。

圖像Ping最經常使用於跟蹤用戶點擊頁面或動態廣告曝光次數。圖像Ping有兩個主要的缺點,一是隻能發送GET請求,二是沒法訪問服務器的響應文本。所以,圖像Ping只能用於瀏覽器與服務器間的單向通訊。

JSONP

JSONP是JSON with padding(填充式JSON或參數JSON)的簡寫,是應用JSON的一種新方法,在後來的web服務中很是流行的。JSONP看起來與JSON差很少,只不過被包含在函數調用中的JSON,就像下面這樣:
callback({「name」:」Nicholas」});
JSONP由兩部分組成:回調函數和數據。回調函數是當響應到來時應該在頁面中調用的函數。回調函數的名字通常是在請求中指定的。而數據就是傳入回調函數中的JSON數據。下面是一個典型的JSONP請求:

http://freegeoip.net/json/?callback=handleResponse

這個URL是在請求一個JSONP地理定位服務。經過查詢字符串來指定JSONP服務的回調參數是很常見的,就像上面URL所示,這裏的回調函數的名字叫handleResponse()
JSONP是經過動態<script>元素來使用的,使用時能夠爲src屬性指定一個跨域URL。這裏的<script>元素與<img>元素相似,都有能力不受限制地從其餘域加載資源。由於JSONP是有效的JavaScript代碼,因此在請求完成後,即在JSONP響應加載到頁面中之後,就會當即執行。例如:

function handleResponse(response){
    console.log('you are at ip'+response.ip+',which is in'+response.city+','+response.region_name);
}
var script=document.createElement('script');
script.src='https://ipstack.com/?callback=handleResponse';
document.body.insertBefore(script, document.body.firstChild);

這個例子經過查詢地理定位服務來顯示你的IP地址和位置信息。

JSONP之因此在開發人員中極爲流行,主要緣由是它很是簡單易用。與圖像Ping相比,它的優勢在於可以直接訪問響應文本,支持在瀏覽器與服務器之間雙向通訊。不過,JSONP也有兩點不足:
首先,JSONP是從其餘域中加載代碼執行。若是其餘域不安全,極可能會在響應中夾帶一些惡意代碼,而此時除了徹底放棄JSONP調用以外,沒有辦法追究。所以在使用不是你本身運維的Web服務時,必定得保證它安全可靠。
其次,要肯定JSONP請求是否失敗並不容易。雖然HTML5給<script>元素新增了一個onerror事件處理程序,但目前尚未獲得任何瀏覽器支持。爲此,開發人員不得不使用計時器檢測指定時間內是否接收到了響應。但就算這樣也不能盡如人意,畢竟不是每一個用戶上網速度和帶寬都同樣。

Comet

Comet指的是一種更高級的Ajax技術(常常也有人稱爲「服務器推送」)。Ajax是一種從頁面像服務器請求數據的技術,而Comet則是一種服務器向頁面推送數據的技術。Comet可以讓信息近乎實時地被推送到頁面上,很是適合處理體育比賽的分數和股票報價。
有兩種實現Comet的方式:長輪詢和流。長輪詢是傳統輪詢(也沒有稱爲短輪詢)的一個翻版,即瀏覽器定時向服務器發送請求,看有沒有更新的數據。如圖展現短輪詢的時間線:
屏幕快照 2020-05-12 下午12.12.49.png
長輪詢把短輪詢顛倒了一下。頁面發起一個服務器的請求,而後服務器一直保持鏈接打開,直到有數據可發送。發送完數據後,瀏覽器關閉鏈接,隨即又發起一個到服務器的新請求,這一過程在頁面打開期間一直持續不斷。如圖展現了長輪詢的時間線:
屏幕快照 2020-05-12 下午12.14.55.png
不管是短輪詢仍是長輪詢,瀏覽器都要在接受數據以前,先發起對服務器的鏈接。二者最大的區別在於服務器如何發送數據。短輪詢是服務器當即發送響應,不管數據是否有效,而長輪詢是等待發送響應。輪詢的優點是全部瀏覽器都支持,由於使用XHR對象和setTimeout()就能實現。而你要作的就是決定何時發送請求。

第二種流行的comet實現是HTTP流。流不一樣於上述兩種輪詢,由於它在頁面的整個生命週期內只使用一個HTTP鏈接。具體來講,就是瀏覽器向服務器發送一個請求,而服務器保持鏈接打開,而後週期性地向瀏覽器發送數據。使用XHR對象實現HTTP流的典型代碼以下所示:

function createStreamingClient(url,progress,finished) {
    var xhr=new XMLHttpRequest();
    received=0;
    xhr.open("get",url,true);
    xhr.onreadystatechange=function () {
        var result;
        if(xhr.readyState==3){
            //只取得最新數據並調整計數器
            result=xhr.responseText.substring(received);
            received+=result.length;
            //調用progress回調函數
            progress(result);
        }else if (xhr.readyState==4){
            finished(xhr.responseText)
        }
    };
    xhr.send(null);
    return xhr;
}
var client=createStreamingClient("https://developer.mozilla.org/en-US/docs/Web/API/XDomainRequest",function (data) {
    alert("Received:"+data);
},function (data) {
    alert("Done!");
    })

這個createStreamingClient()函數接收三個參數:要鏈接的URL、在接收到數據時調用的函數以及關閉鏈接時調用的函數。有時候,當鏈接關閉時,頗有可能還須要從新創建,因此關注鏈接何時關閉仍是有必要的。
只要readystatechange事件發生,並且readyState值爲3,就對responseText進行分割以取得最新數據。這裏的received變量用於記錄已經處理了多少字符,每次readyState值爲3時都遞增,而後,經過progress回調函數來處理傳入的新數據。而當readyState值爲4時,則執行finished回調函數,傳入響應返回的內容。

這個簡單的例子能在大多數瀏覽器中正常運行(IE除外),但管理Comet的鏈接很容易出錯,須要時間不斷改進才能達到完美。Comet是將來Web 的一個重要組成部分,爲了簡化這一技術,又爲Comet建立了兩個新的接口。

其餘跨域技術

SSE(服務器發送事件)
Web Sockets
SSE+Web Sockets

HTTP

http詳解及問題

HTTP協議

概況

HTTP是超文本傳輸協議,它定義了客戶端和服務器之間的交換報文的格式和方式,默認使用80端口。它使用TCP做爲傳輸層協議,保證了數據傳輸的可靠性。

HTTP 是一個無狀態的協議,HTTP 服務器不會保存關於客戶的任何信息。

HTTP 有兩種鏈接模式,一種是持續鏈接,一種非持續鏈接。非持續鏈接指的是服務器必須爲每個請求的對象創建和維護 一個全新的鏈接。持續鏈接下,TCP 鏈接默認不關閉,能夠被多個請求複用。採用持續鏈接的好處是能夠避免每次創建 TCP 鏈接三次握手時所花費的時間。在 HTTP1.0 之前使用的非持續的鏈接,可是能夠在請求時,加上 Connection: keep-a live 來要求服務器不要關閉 TCP 鏈接。HTTP1.1 之後默認採用的是持續的鏈接。目前對於同一個域,大多數瀏覽器支持 同時創建 6 個持久鏈接。

HTTP 請求報文

參考
HTTP 報文有兩種,一種是請求報文,一種是響應報文。
HTTP 請求報文的格式以下:
屏幕快照 2020-05-14 下午7.45.27.png
HTTP 請求報文的第一行叫作請求行,後面的行叫作首部行,首部行後還能夠跟一個實體主體。請求首部以後有一個空行,這 個空行不能省略,它用來劃分首部與實體。

  • 請求行由請求方法字段、URL字段和HTTP協議版本字段3個字段組成,它們用空格分隔。好比 GET /data/info.html HTTP/1.1
HTTP客戶程序,向服務器發送請求的時候必須指明請求類型(通常是GET或者 POST)。若有必要,客戶程序還能夠選擇發送其餘的請求頭。大多數請求頭並非必需的,但Content-Length除外。對於POST請求來講 Content-Length必須出現。
常見的請求頭字段含義:
Accept: 瀏覽器可接受的MIME類型。
Accept-Charset:瀏覽器可接受的字符集。
Accept-Encoding:瀏覽器可以進行解碼的數據編碼方式,好比gzip。Servlet可以向支持gzip的瀏覽器返回經gzip編碼的HTML頁面。許多情形下這能夠減小5到10倍的下載時間。
Accept-Language:瀏覽器所但願的語言種類,當服務器可以提供一種以上的語言版本時要用到。
Authorization:受權信息,一般出如今對服務器發送的WWW-Authenticate頭的應答中。
Content-Length:表示請求消息正文的長度。
Host: 客戶機經過這個頭告訴服務器,想訪問的主機名。Host頭域指定請求資源的Intenet主機和端口號,必須表示請求url的原始服務器或網關的位置。HTTP/1.1請求必須包含主機頭域,不然 系統會以400狀態碼返回。
If-Modified-Since:客戶機經過這個頭告訴服務器,資源的緩存時間。只有當所請求的內容在指定的時間後又通過修改才返回它,不然返回304「Not Modified」應答。
Referer:客戶機經過這個頭告訴服務器,它是從哪一個資源來訪問服務器的(防盜鏈)。包含一個URL,用戶從該URL表明的頁面出發訪問當前請求的頁面。
User-Agent:User-Agent頭域的內容包含發出請求的用戶信息。瀏覽器類型,若是Servlet返回的內容與瀏覽器類型有關則該值很是有用。
Cookie:客戶機經過這個頭能夠向服務器帶數據,這是最重要的請求頭信息之一。
Pragma:指定「no-cache」值表示服務器必須返回一個刷新後的文檔,即便它是代理服務器並且已經有了頁面的本地拷貝。
From:請求發送者的email地址,由一些特殊的Web客戶程序使用,瀏覽器不會用到它。
Connection:處理完此次請求後是否斷開鏈接仍是繼續保持鏈接。若是Servlet看到這裏的值爲「Keep- Alive」,或者看到請求使用的是HTTP 1.1(HTTP 1.1默認進行持久鏈接),它就能夠利用持久鏈接的優勢,當頁面包含多個元素時(例如Applet,圖片),顯著地減小下載所須要的時間。要實現這一點,Servlet須要在應答中發送一個Content-Length頭,最簡單的實現方法是:先把內容寫入 ByteArrayOutputStream,而後在正式寫出內容以前計算它的大小
Range:Range頭域能夠請求實體的一個或者多個子範圍。例如,
表示頭500個字節:bytes=0-499
表示第二個500字節:bytes=500-999
表示最後500個字節:bytes=-500
表示500字節之後的範圍:bytes=500-
第一個和最後一個字節:bytes=0-0,-1
同時指定幾個範圍:bytes=500-600,601-999
可是服務器能夠忽略此請求頭,若是無條件GET包含Range請求頭,響應會以狀態碼206(PartialContent)返回而不是以200 (OK)。
UA-Pixels,UA-Color,UA-OS,UA-CPU:由某些版本的IE瀏覽器所發送的非標準的請求頭,表示屏幕大小、顏色深度、操做系統和CPU類型。
  • 方法字段就是HTTP使用的請求方法,方法字段能夠取幾種不一樣的值,通常有 GET、POST、HEAD、PUT 和 DELETE。
通常GET方法只被用於向服務器獲取數據。
POST 方法用於將實體提交到指定的資源,一般會形成服務器資源的修改。
HEAD方法與 GET 方法相似,可是在返回的響應 中,不包含請求對象。PUT 方法用於上傳文件到服務器,DELETE 方法用於刪除服務器上的對象。雖然請求的方法不少,但更多表達的是一種語義上的區別,並非說 POST 能作的事情,GET就不能作了,主要看咱們如何選擇。

HTTP 響應報文

HTTP 報文有兩種,一種是請求報文,一種是響應報文。
HTTP 響應報文的格式以下:
屏幕快照 2020-05-14 下午7.45.48.png

HTTP響應報文也由三部分組成:響應行、響應頭、響應體

  • 響應行通常由協議版本、狀態碼及其描述組成 好比 HTTP/1.1 200 OK

其中協議版本HTTP/1.1或者HTTP/1.0,200就是它的狀態碼,OK則爲它的描述。

//常見狀態碼:
100~199:表示成功接收請求,要求客戶端繼續提交下一次請求才能完成整個處理過程。
200~299:表示成功接收請求並已完成整個處理過程。經常使用200
300~399:爲完成請求,客戶需進一步細化請求。例如:請求的資源已經移動一個新地址、經常使用302(意味着你請求我,我讓你去找別人),307和304(我不給你這個資源,本身拿緩存)
400~499:客戶端的請求有錯誤,經常使用404(意味着你請求的資源在web服務器中沒有)403(服務器拒絕訪問,權限不夠)
500~599:服務器端出現錯誤,經常使用500
  • 響應頭用於描述服務器的基本信息,以及數據的描述,服務器經過這些數據的描述信息,能夠通知客戶端如何處理等一下子它回送的數據。

設置HTTP響應頭每每和狀態碼結合起來。例如,有好幾個表示「文檔位置已經改變」的狀態代碼都伴隨着一個Location頭,而401(Unauthorized)狀態代碼則必須伴隨一個WWW-Authenticate頭。然而,即便在沒有設置特殊含義的狀態代碼時,指定應答頭也是頗有用的。應答頭能夠用來完成:設置Cookie,指定修改日期,指示瀏覽器按照指定的間隔刷新頁面,聲明文檔的長度以便利用持久HTTP鏈接,……等等許多其餘任務。

常見的響應頭字段含義:
Allow:服務器支持哪些請求方法(如GET、POST等)。
Content-Encoding:文檔的編碼(Encode)方法。只有在解碼以後才能夠獲得Content-Type頭指定的內容類型。利用gzip壓縮文檔可以顯著地減小HTML文檔的下載時間。 Java的GZIPOutputStream能夠很方便地進行gzip壓縮,但只有Unix上的Netscape和Windows上的IE四、IE5才支持它。所以,Servlet應該經過查看Accept-Encoding頭(即request.getHeader(「Accept- Encoding」))檢查瀏覽器是否支持gzip,爲支持gzip的瀏覽器返回經gzip壓縮的HTML頁面,爲其餘瀏覽器返回普通頁面。
Content-Length:表示內容長度。只有當瀏覽器使用持久HTTP鏈接時才須要這個數據。若是你想要利用持久鏈接的優點,能夠把輸出文檔寫入 ByteArrayOutputStram,完成後查看其大小,而後把該值放入Content-Length頭,最後經過byteArrayStream.writeTo(response.getOutputStream()發送內容。
Content- Type:表示後面的文檔屬於什麼MIME類型。Servlet默認爲text/plain,但一般須要顯式地指定爲text/html。因爲常常要設置 Content-Type,所以HttpServletResponse提供了一個專用的方法setContentType。
Date:當前的GMT時間,例如,Date:Mon,31Dec200104:25:57GMT。Date描述的時間表示世界標準時,換算成本地時間,須要知道用戶所在的時區。你能夠用setDateHeader來設置這個頭以免轉換時間格式的麻煩。
Expires:告訴瀏覽器把回送的資源緩存多長時間,-1或0則是不緩存。
Last-Modified:文檔的最後改動時間。客戶能夠經過If-Modified-Since請求頭提供一個日期,該請求將被視爲一個條件GET,只有改動時間遲於指定時間的文檔纔會返回,不然返回一個304(Not Modified)狀態。Last-Modified也可用setDateHeader方法來設置。
Location:這個頭配合302狀態碼使用,用於重定向接收者到一個新URI地址。表示客戶應當到哪裏去提取文檔。Location一般不是直接設置的,而是經過HttpServletResponse的sendRedirect方法,該方法同時設置狀態代碼爲302。
Refresh:告訴瀏覽器隔多久刷新一次,以秒計。
Server:服務器經過這個頭告訴瀏覽器服務器的類型。Server響應頭包含處理請求的原始服務器的軟件信息。此域能包含多個產品標識和註釋,產品標識通常按照重要性排序。Servlet通常不設置這個值,而是由Web服務器本身設置。
Set-Cookie:設置和頁面關聯的Cookie。Servlet不該使用response.setHeader(「Set-Cookie」, …),而是應使用HttpServletResponse提供的專用方法addCookie。
Transfer-Encoding:告訴瀏覽器數據的傳送格式。
WWW-Authenticate:客戶應該在Authorization頭中提供什麼類型的受權信息?在包含401(Unauthorized)狀態行的應答中這個頭是必需的。例如,response.setHeader(「WWW-Authenticate」, 「BASIC realm=\」executives\」「)。注意Servlet通常不進行這方面的處理,而是讓Web服務器的專門機制來控制受密碼保護頁面的訪問。
注:設置應答頭最經常使用的方法是HttpServletResponse的setHeader,該方法有兩個參數,分別表示應答頭的名字和值。和設置狀態代碼類似,設置應答頭應該在發送任何文檔內容以前進行。
setDateHeader方法和setIntHeadr方法專門用來設置包含日期和整數值的應答頭,前者避免了把Java時間轉換爲GMT時間字符串的麻煩,後者則避免了把整數轉換爲字符串的麻煩。
HttpServletResponse還提供了許多設置
setContentType:設置Content-Type頭。大多數Servlet都要用到這個方法。
setContentLength:設置Content-Length頭。對於支持持久HTTP鏈接的瀏覽器來講,這個函數是頗有用的。
addCookie:設置一個Cookie(Servlet API中沒有setCookie方法,由於應答每每包含多個Set-Cookie頭)。
  • 響應體就是響應的消息體,若是是純數據就是返回純數據,若是請求的是HTML頁面,那麼返回的就是HTML代碼,若是是JS就是JS代碼,如此之類。

首部行

首部能夠分爲四種首部,請求首部、響應首部、通用首部和實體首部。通用首部和實體首部在請求報文和響應報文中均可以設置,區別在於請求首部和響應首部。

  • 常見的請求首部有 Accept 可接收媒體資源的類型、Accept-Charset 可接收的字符集、Host 請求的主機名。
  • 常見的響應首部有 ETag 資源的匹配信息,Location 客戶端重定向的 URI。
  • 常見的通用首部有 Cache-Control 控制緩存策略、Connection 管理持久鏈接。
  • 常見的實體首部有 Content-Length 實體主體的大小、Expires 實體主體的過時時間、Last-Modified 資源的最後修改時間。

HTTP/1.1 協議缺點

HTTP/1.1 默認使用了持久鏈接,多個請求能夠複用同一個 TCP 鏈接,可是在同一個 TCP 鏈接裏面,數據請求的通訊次序 是固定的。服務器只有處理完一個請求的響應後,纔會進行下一個請求的處理,若是前面請求的響應特別慢的話,就會形成許 多請求排隊等待的狀況,這種狀況被稱爲「隊頭堵塞」。隊頭阻塞會致使持久鏈接在達到最大數量時,剩餘的資源須要等待其餘 資源請求完成後才能發起請求。

爲了不這個問題,一個是減小請求數,一個是同時打開多個持久鏈接。這就是咱們對網站優化時,使用雪碧圖、合併腳本的緣由。

HTTP/2協議

2009 年,谷歌公開了自行研發的 SPDY 協議,主要解決 HTTP/1.1 效率不高的問題。這個協議在 Chrome 瀏覽器上證實 可行之後,就被看成 HTTP/2 的基礎,主要特性都在 HTTP/2 之中獲得繼承。2015 年,HTTP/2 發佈。

HTTP/2 主要有如下新的特性:

  • 二進制協議

HTTP/2 是一個二進制協議。在 HTTP/1.1 版中,報文的頭信息必須是文本(ASCII 編碼),數據體能夠是文本,也能夠是 二進制。HTTP/2 則是一個完全的二進制協議,頭信息和數據體都是二進制,而且統稱爲"幀",能夠分爲頭信息幀和數據幀。 幀的概念是它實現多路複用的基礎。

  • 多路複用

HTTP/2 實現了多路複用,HTTP/2 仍然複用 TCP 鏈接,可是在一個鏈接裏,客戶端和服務器均可以同時發送多個請求或回 應,並且不用按照順序一一發送,這樣就避免了"隊頭堵塞"的問題。

  • 數據流

HTTP/2 使用了數據流的概念,由於 HTTP/2 的數據包是不按順序發送的,同一個鏈接裏面連續的數據包,可能屬於不一樣的 請求。所以,必需要對數據包作標記,指出它屬於哪一個請求。HTTP/2 將每一個請求或迴應的全部數據包,稱爲一個數據流。每 個數據流都有一個獨一無二的編號。數據包發送的時候,都必須標記數據流 ID ,用來區分它屬於哪一個數據流。

  • 頭信息壓縮

HTTP/2 實現了頭信息壓縮,因爲 HTTP 1.1 協議不帶有狀態,每次請求都必須附上全部信息。因此,請求的不少字段都是 重複的,好比 Cookie 和 User Agent ,如出一轍的內容,每次請求都必須附帶,這會浪費不少帶寬,也影響速度。

HTTP/2 對這一點作了優化,引入了頭信息壓縮機制。一方面,頭信息使用 gzip 或 compress 壓縮後再發送;另外一方面, 客戶端和服務器同時維護一張頭信息表,全部字段都會存入這個表,生成一個索引號,之後就不發送一樣字段了,只發送索引 號,這樣就能提升速度了。

  • 服務器推送

HTTP/2 容許服務器未經請求,主動向客戶端發送資源,這叫作服務器推送。使用服務器推送,提早給客戶端推送必要的資源 ,這樣就能夠相對減小一些延遲時間。這裏須要注意的是 http2 下服務器主動推送的是靜態資源,和 WebSocket 以及使用 SSE 等方式向客戶端發送即時數據的推送是不一樣的。

HTTP/2 協議缺點

由於 HTTP/2 使用了多路複用,通常來講同一域名下只須要使用一個 TCP 鏈接。因爲多個數據流使用同一個 TCP 鏈接,遵 守同一個流量狀態控制和擁塞控制。只要一個數據流遭遇到擁塞,剩下的數據流就無法發出去,這樣就致使了後面的全部數據都 會被阻塞。HTTP/2 出現的這個問題是因爲其使用 TCP 協議的問題,與它自己的實現其實並無多大關係。

HTTP/3 協議

因爲 TCP 自己存在的一些限制,Google 就開發了一個基於 UDP 協議的 QUIC 協議,而且使用在了 HTTP/3 上。 QUIC 協議在 UDP 協議上實現了多路複用、有序交付、重傳等等功能

HTTPS 協議

HTTP 存在的問題

HTTP 報文使用明文方式發送,可能被第三方竊聽。
HTTP 報文可能被第三方截取後修改通訊內容,接收方沒有辦法發現報文內容的修改。
HTTP 還存在認證的問題,第三方能夠冒充他人蔘與通訊。

HTTPS 簡介

HTTPS 指的是超文本傳輸安全協議,HTTPS 是基於 HTTP 協議的,不過它會使用 TLS/SSL 來對數據加密。使用 TLS/ SSL 協議,全部的信息都是加密的,第三方沒有辦法竊聽。而且它提供了一種校驗機制,信息一旦被篡改,通訊的雙方會立 刻發現。它還配備了身份證書,防止身份被冒充的狀況出現。

TLS 握手過程

  1. 第一步,客戶端向服務器發起請求,請求中包含使用的協議版本號、生成的一個隨機數、以及客戶端支持的加密方法。
  2. 第二步,服務器端接收到請求後,確認雙方使用的加密方法、並給出服務器的證書、以及一個服務器生成的隨機數。
  3. 第三步,客戶端確認服務器證書有效後,生成一個新的隨機數,並使用數字證書中的公鑰,加密這個隨機數,而後發給服務器。而且還會提供一個前面全部內容的 hash 的值,用來供服務器檢驗。
  4. 第四步,服務器使用本身的私鑰,來解密客戶端發送過來的隨機數。並提供前面全部內容的 hash 值來供客戶端檢驗。
  5. 第五步,客戶端和服務器端根據約定的加密方法使用前面的三個隨機數,生成對話祕鑰,之後的對話過程都使用這個祕鑰來加密信息。

實現原理


TLS 的握手過程主要用到了三個方法來保證傳輸的安全。

首先是對稱加密的方法,對稱加密的方法是,雙方使用同一個祕鑰對數據進行加密和解密。可是對稱加密的存在一個問題,就 是如何保證祕鑰傳輸的安全性,由於祕鑰仍是會經過網絡傳輸的,一旦祕鑰被其餘人獲取到,那麼整個加密過程就毫無做用了。 這就要用到非對稱加密的方法。

非對稱加密的方法是,咱們擁有兩個祕鑰,一個是公鑰,一個是私鑰。公鑰是公開的,私鑰是保密的。用私鑰加密的數據,只 有對應的公鑰才能解密,用公鑰加密的數據,只有對應的私鑰才能解密。咱們能夠將公鑰公佈出去,任何想和咱們通訊的客戶, 均可以使用咱們提供的公鑰對數據進行加密,這樣咱們就可使用私鑰進行解密,這樣就能保證數據的安全了。可是非對稱加 密有一個缺點就是加密的過程很慢,所以若是每次通訊都使用非對稱加密的方式的話,反而會形成等待時間過長的問題。

所以咱們可使用對稱加密和非對稱加密結合的方式,由於對稱加密的方式的缺點是沒法保證祕鑰的安全傳輸,所以咱們能夠 非對稱加密的方式來對對稱加密的祕鑰進行傳輸,而後之後的通訊使用對稱加密的方式來加密,這樣就解決了兩個方法各自存 在的問題。

可是如今的方法也不必定是安全的,由於咱們沒有辦法肯定咱們獲得的公鑰就必定是安全的公鑰。可能存在一箇中間人,截取 了對方發給咱們的公鑰,而後將他本身的公鑰發送給咱們,當咱們使用他的公鑰加密後發送的信息,就能夠被他用本身的私鑰 解密。而後他假裝成咱們以一樣的方法向對方發送信息,這樣咱們的信息就被竊取了,然而咱們本身還不知道。

爲了解決這樣的問題,咱們可使用數字證書的方式,首先咱們使用一種 Hash 算法來對咱們的公鑰和其餘信息進行加密生成 一個信息摘要,而後讓有公信力的認證中心(簡稱 CA )用它的私鑰對消息摘要加密,造成簽名。最後將原始的信息和簽名合 在一塊兒,稱爲數字證書。當接收方收到數字證書的時候,先根據原始信息使用一樣的 Hash 算法生成一個摘要,而後使用公證 處的公鑰來對數字證書中的摘要進行解密,最後將解密的摘要和咱們生成的摘要進行對比,就能發現咱們獲得的信息是否被更改 了。這個方法最要的是認證中心的可靠性,通常瀏覽器裏會內置一些頂層的認證中心的證書,至關於咱們自動信任了他們,只有 這樣咱們才能保證數據的安全。

事件綁定

addEventListener參數

element.addEventListener(type, function, useCapture)
【事件類型】,【事件處理程序】,【可選。布爾值,指定事件是否在捕獲或冒泡階段執行。 true:事件句柄在捕獲階段執行false:(默認)事件句柄在冒泡階段執行

捕獲

捕獲則和冒泡相反,目標元素被觸發後,會從目標元素的最頂層的祖先元素事件往下執行到目標元素爲止。
addEventListener函數的第三個參數均改成true,事件爲捕獲階段執行。
注意: 在事件處理程序中刪除目標元素也能阻止事件冒泡,目標元素在文檔中是事件冒泡的前提

冒泡

冒泡是從下向上,DOM元素綁定的事件被觸發時,此時該元素爲目標元素,目標元素執行後,它的的祖元素綁定的事件會向上順序執行。
addEventListener函數的第三個參數設置爲false說明不爲捕獲事件,即爲冒泡事件。

當一個元素綁定兩個事件,一個冒泡,一個捕獲

首先,不管是冒泡事件仍是捕獲事件,元素都會先執行捕獲階段。
從上往下,若有捕獲事件,則執行;一直向下到目標元素後,從目標元素開始向上執行冒泡元素,即第三個參數爲true表示捕獲階段調用事件處理程序,若是是false則是冒泡階段調用事件處理程序。(在向上執行過程當中,已經執行過的捕獲事件再也不執行,只執行冒泡事件。

事件執行順序

執行次數:綁定了幾個事件便執行幾回
例如:two元素綁定了兩個不一樣事件,點擊two都會執行這兩個事件。而執行順序有所差別。

<div id='one'> 
    <div id='two'> 
        <div id='three'> 
            <div id='four'> 
            </div> 
        </div> 
    </div>
</div>
one.addEventListener('click',function(){
alert('one');
},true);
two.addEventListener('click',function(){
alert('two,bubble');
},false);
two.addEventListener('click',function(){
alert('two,capture');
},true);
three.addEventListener('click',function(){
alert('three,bubble');
},true);
four.addEventListener('click',function(){
alert('four');
},true);
一、若是two爲目標元素,目標元素的同類型事件按順序執行,而其餘元素根據W3C的標準執行,即先捕獲後冒泡。

點擊two執行結果:
one(由於是two的父元素支持捕獲事件因此先執行)
two,bubble
two,capture(順序執行,注意逗號不是間隔,是輸出內容。)

二、若是目標元素不是two,則two的同類型事件按先捕獲後冒泡觸發執行,也就是跟前面討論的執行過程是同樣的,只不過兩個事件都綁定在同一個DOM元素上。

點擊three執行結果:
one
two,capture
three,bubble
two,bubble

因此

綁定在被點擊元素的事件是按照代碼順序發生
其餘元素經過冒泡或者捕獲「感知」的事件。
按照W3C的標準,先發生捕獲事件,後發生冒泡事件。全部事件的順序是:
其餘元素捕獲階段事件 -> 本元素代碼順序事件 -> 其餘元素冒泡階段事件
相關文章
相關標籤/搜索