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的标准,先发生捕获事件,后发生冒泡事件。全部事件的顺序是:
其余元素捕获阶段事件 -> 本元素代码顺序事件 -> 其余元素冒泡阶段事件
相关文章
相关标签/搜索