13

如何解决跨域问题:

跨域原因:由于浏览器的同源策略限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源。在脚本中发起HTTP请求,出于安全考虑,会被浏览器限制,html中通过标签请求不存跨域:img,video,script文件,css文件等。
同源策略:同源策略是客户端脚本(尤其是Javascript)的重要的安全度量标准。它最早出自Netscape Navigator2.0,其目的是防止某个文档或脚本从多个不同源装载。同源策略指的是:协议,域名,端口相同,同源策略是一种安全协议。一段脚本只能读取来自同一来源的窗口和文档的属性。
为什么要有同源限制?
我们举例说明:比如一个黑客程序,他利用Iframe把真正的银行登录页面嵌到他的页面上,当你使用真实的用户名,密码登录时,他的页面就可以通过Javascript读取到你的表单中input中的内容,这样用户名,密码就轻松到手了。

跨域的几种方式

1>、JSONP:json+padding(内填充),顾名思义,就是把JSON填充到一个盒子里。
原理:利用HTML的<script>标签天生可以跨域这一特点,通过动态创建script标签,用其加载另一个域的JSON数据,加载完成后会自动运行一个回调函数通知调用者。此过程需要另一个域的服务端支持,所以这种方式实现的跨域并不是任意的。

优点:兼容性好,简单易用,支持浏览器与服务器双向通信。
缺点:只支持GET请求和JSON格式的数据,传输的数据有限制。

/**原生Js:**/

<button id="btn">click</button>
<script type="text/javascript">
    function $(str){
        return document.getElementById(str)
    }
    function CreateScript(src) {
        var Scrip=document.createElement('script');
        Scrip.src=src;
        document.body.appendChild(Scrip);
    }
    function jsonpcallback(json) {
            console.log(json);//Object { email="中国", email2="中国222"}
    }
    $('btn').onclick=function(){
      CreateScript("http://localhost:51335/somejson?callback=jsonpcallback")    
    }
</script>

/** jQuery获取jsonp **/

$("#getJsonpByJquery").click(function () {
    $.ajax({
        url: 'http://localhost:2701/home/somejsonp',
        dataType: "jsonp",
        jsonp: "callback",
        success: function (data) {
            console.log(data)
        }
    })
})

进阶问题
1,JSONP需要动态创建script标签,需不需要处理这些script元素?怎么处理?
需要,可以监听script标签的加载状态,当失败或加载完成后移除script标签并移除标签上的监听事件,以及挂载在window上的回调函数。

2,JSONP请求的时候,服务器发生错误该怎么办,前端怎么处理这个错误?
一般前端框架都会对跨域请求失败是进行处理,比如JQuery中,当使用ajax或getJSON发送请求后会返回一个jqXHR对象。该对象实现了Promise协议,所以我们可以使用它的done、fail、always等接口来处理回调。例如我们可以用在它的fail回调中进行请求失败时的错误处理:

var xhr = $.getJSON(...);
xhr.fail(function(jqXHR, textStatus, ex) {
    alert('request failed, cause: ' + ex.message);
});

当遇到“非正常错误”时,除了IE7、8以外,JQuery的JSONP在较新的浏览器中全部会“静默失败”。但很多时候我们希望能够捕获和处理这种错误。实际上在这些浏览器中,<script>标签在遇到这些错误时会触发error事件。例如如果是我们自己来实现JSONP的话可以这样:

var ele = document.createElement('script');
ele.type = "text/javascript";
ele.src = '...';
ele.onerror = function() {
    alert('error');
};
ele.onload = function() {
    alert('load');
};
document.body.appendChild(ele);

2>、CORS:服务器端对于CORS的支持,CORS原理只需要向响应头header中注入Access-Control-Allow-Origin。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。与JSONP不同,CORS 除了GET要求方法以外也支援其他的HTTP要求。用CORS可以让网页设计师用一般的XMLHttpRequest,这种方式的错误处理比JSONP要来的好。

/** 服务端设置 **/
response.setHeader("Access-Control-Allow-Origin", "*");

response.setHeader("Access-Control-Allow-Origin", "");这句代码中代码,服务器允许任何人访问。当然可以设置规定访问的域名。比如只允许http://localhost:8080/crcp这个域下的访问。则把*代替成这个域名即可。

缺点:CORS实现起来比较简单,但是缺点是支持浏览器有限,目前支持的浏览器版本如下

clipboard.png

3>、通过修改document.domain来跨子域:将子域和主域的document.domain设为同一个主域.前提条件:这两个域名必须属于同一个基础域名!而且所用的协议,端口都要一致,否则无法利用document.domain进行跨域。

4>、window.name实现跨域:window.name 的美妙之处:name 值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。
原理:当在浏览器中打开一个页面,或者在页面中添加一个iframe时即会创建一个对应的window对象,当页面加载另一个新的页面时,window的name属性是不会变的。这样就可以利用在页面动态添加一个iframe然后src加载数据页面,在数据页面将需要的数据赋值给window.name。然而此时承载iframe的parent页面还是不能直接访问,不在同一域下iframe的name属性,这时只需要将iframe再加载一个与承载页面同域的空白页面,即可对window.name进行数据读取。
www.test.com下a.html页

<script type="text/javascript">

        var a=document.getElementsByTagName("button")[0];

        a.onclick=function(){                               //button添加click事件
            var inf=document.createElement("iframe");       //创建iframe
            inf.src="http://www.domain.com/window.name/b.html"+"?h=5"  //加载数据页www.domain.com/window.name/b.html同事携带参数h=5
            var body=document.getElementsByTagName("body")[0];
            body.appendChild(inf);                          //引入a页面

            inf.onload=function(){
                inf.src='http://www.test.com/b.html'       //iframe加载完成,加载www.test.com域下边的空白页b.html
                console.log(inf.contentWindow.name)        //输出window.name中的数据
                body.removeChild(inf)                      //清除iframe
            }
        }
</script>

www.domain.com下b.html页

<script>
        var str=window.location.href.substr(-1,1);      //获取url中携带的参数值
        $.ajax({
            type:"get",
            url:"http://www.domain.com/a.php"+"?m="+str, //通过ajax将查询参数传给php页面
            async:true,
            success:function(res){
                window.name=res                         //将接收到的查询数据赋值给window.name
            },
            error:function(){
                window.name='error'                      //..
            }
        });
</script>

5>、window.postMessage方法来跨域
www.test.com下a.html页

<script>
        /*
        * window.postMessage是html5中的方法
        * */
        window.onload = function () {
            var oInput = document.getElementById('input1');
            var oButton = document.getElementById('btn1');
            oButton.onclick = function () {
                var data = oInput.value;
                window.frames[0].postMessage(data, '*');
            }
        }
</script>
<iframe src="http://www.lamport.me/data2.html" style="display:none" frameborder="0"></iframe>
<button id="btn1">点击我通过iframe框架向http://www.lamport.me/data2.html页面发送并返回数据</button>

www.domain.com下b.html页

<script>
    window.onmessage = function(e) {
        e = e || event;
        alert('我接受到来自外太空的数据:' + e.data);
    }
</script>

6>、另可通过filder工具,或者本地起node来实现跨域


XML和JSON的区别?

XML:扩展标记语言,使用DTD文档类型定义来组织数据,格式统一,适合Web传输。
优点:
1.格式统一,符合标准;
2.容易与其他系统进行远程交互,数据共享方便;
3.扩展性好;
4.描述性比JSON好;
缺点:
1.文件庞大,格式复杂,传输数据量大;
2.客户端不同浏览器解析XML方式不一致,需要重复编写很多代码;
3.服务器端和客户端解析XML花费较多的资源和时间。
JSON:一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性。可在不同平台之间进行数据交换。JSON采用兼容性很高的、完全独立于语言文本格式。
优点:
1,数据格式简单,易于读写,传输数据量较小;
2.易于解析,客户端可以简单通过eval()进行JSON数据的读取;
3.支持多种语言,便于服务端的解析;
缺点:
JSON只提供整体解析方案,而这种方法只在解析较少的数据时才能起到良好的效果;
XML通过SAX解析,可以不需要整个读入文档,就可以对解析出的内容进行处理,是一种逐步解析的方法,也可以随时终止,这种方案很适合于对大量数据的处理。
数据展示比较:

/** XML **/
<?xml version="1.0" encoding="utf-8" ?>
<country>
  <name>中国</name>
  <province>
    <name>黑龙江</name>
    <citys>
      <city>哈尔滨</city>
      <city>大庆</city>
    </citys>    
  </province>
  <province>
    <name>广东</name>
    <citys>
      <city>广州</city>
      <city>深圳</city>
      <city>珠海</city>
    </citys>   
  </province>
  <province>
    <name>台湾</name>
    <citys>
       <city>台北</city>
       <city>高雄</city>
    </citys> 
  </province>
  <province>
    <name>新疆</name>
    <citys>
      <city>乌鲁木齐</city>
    </citys>
  </province>
</country>

 /** JSON **/
 var country =
    {
        name: "中国",
        provinces: [
        { name: "黑龙江", citys: { city: ["哈尔滨", "大庆"]} },
        { name: "广东", citys: { city: ["广州", "深圳", "珠海"]} },
        { name: "台湾", citys: { city: ["台北", "高雄"]} },
        { name: "新疆", citys: { city: ["乌鲁木齐"]} }
        ]
    }

说说TCP传输的三次握手四次挥手策略?

ACK:TCP协议规定,只有ACK=1时有效,也规定连接建立后所有发送的报文的ACK必须为1;
SYN: 在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文。对方若同意建立连接,则应在响应报文中使SYN=1和ACK=1. 因此, SYN置1就表示这是一个连接请求或连接接受报文。
FIN:即完,终结的意思, 用来释放一个连接。当 FIN = 1 时,表明此报文段的发送方的数据已经发送完毕,并要求释放连接。

tcp标志位,有6种标示
1.SYN(synchronous建立联机)
2.ACK(acknowledgement 确认)
3.PSH(push传送)
4.FIN(finish结束)
5.RST(reset重置)
6.URG(urgent紧急) Sequence number(顺序号码) Acknowledge number(确认号码)

状态详解
1.CLOSED: 表示初始状态。
2.LISTEN: 这个也是非常容易理解的一个状态,表示服务器端的某个SOCKET处于监听状态,可以接受连接了。
3.SYN_RCVD: 这个状态表示接受到了SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本
上用netstat你是很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次TCP握手过程中最后一个ACK报文不予发送。因此这种状态
时,当收到客户端的ACK报文后,它会进入到ESTABLISHED状态。
4.SYN_SENT: 这个状态与SYN_RCVD遥想呼应,当客户端SOCKET执行CONNECT连接时,它首先发送SYN报文,因此也随即它会进入到了SYN_SENT状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。
5.ESTABLISHED:这个容易理解了,表示连接已经建立了。
6.FIN_WAIT_1: 这个状态要好好解释一下,其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别
是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即
进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马
上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。
7.FIN_WAIT_2:上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。
8.TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。
9.CLOSING: 这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的
ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什
么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报
文的情况,也即会出现CLOSING状态,表示双方都正在关闭SOCKET连接。
10.CLOSE_WAIT: 这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对
方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以
close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。
11.LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。

三次握手
1、客户端(Client)向服务端发送SYN包,即SYN=1,ACK=0,随机产生seq number=3626544836,服务端(Serve)接收到SYN包,通过SYN=1,ACK=0 知道要求建立联机;(第一次握手)
2、服务端收到请求后要确认联机信息,向客户端发送SYN包(syn=k),即ack number=3626544837,syn=1,ack=1,随机产生seq=1739326486的包,服务端进入SYN_RECV状态;(第二次握手)
3、客户端接收到服务发回的SYN+ACK包后,检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,再次向服务端发送确认包ACK,即ack number=1739326487,ack=1,此包发送完毕后,服务端接收到后确认seq = seq + 1,ack = 1,则连接建立成功,双方进入ESTABLISHED状态。(第三次握手)

一个完整的三次握手就是:请求---应答----再次确认----服务端收到确认建立连接

建立连接为什么要三次握手(两次确认)
两次确认主要是为了防止已失效的连接请求报文段突然又传送给了服务端,因而产生错误连接。
已失效的连接请求报文段发生情况
1.假设客户端向服务端发送一个建立连接的请求,请求报文由于网络原因在某个网络节点滞留了,客户端长时间没有收到服务端的确认,于是以为请求报文丢失,于是又再一次发送连接请求,然后这次收到确认并成功建立了连接,数据输出完后,释放了连接。
2.在释放连接之后,结果第一次的连接请求到达了服务端,这时服务端会误以为这是客户端又重新发出了一次新的请求,于是向客户端发送确认报文段,同意建立连接。
3.假如没有采用三次握手,服务端这次发送确认后就建立了新的连接,并等待客户端发来请求,可是客户端实际情况并没有发出请求,于是服务端很多资源就这样浪费了。
4.如果采用三次握手,当服务端向客户端发送确认报文段后,客户端并不会再向服务端发送确认,于是服务端就知道客户端并没有要求建立连接。

若在握手过程中某个阶段莫名中断,TCP协议会再次以相同的顺序发送相同的数据包。

四次挥手
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
1、客户端向服务端发送一个FIN,表示自己这方的数据已经发送完毕,可以释放连接。
2、服务端收到FIN后,发回一个ASK,确认已收到释放连接通知,确认序号为收到的序号加1。
3、服务端确认自己这方的数据已经发送完毕后,向客户端发送一个FIN,表示要释放连接。
4、客户端收到FIN后,发回一个ASK报文确认,确认序号为收到的序号加1。

1、为什么建立连接时三次握手,关闭连接是4次握手?

1.这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。

2.但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的.

2.为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?

1.这是因为虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);

2.但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。


TCP和UDP的区别?

TCP(Transmission Control Protocol,传输控制协议)是基于连接的协议,也就是说,在正式收发数据前,必须和对方建立可靠的连接。一个TCP连接必须要经过三次“对话”才能建立起来

UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是面向非连接的协议,它不与对方建立连接,而是直接就把数据包发送过去!
UDP适用于一次只传送少量数据、对可靠性要求不高的应用环境。


创建ajax过程?

1.创建XMLHttpRequest对象,也就是创建一个异步调用对象;
2.通过XMLHttpRequest对象创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息;
3.设置响应HTTP请求状态变化的函数;
4.发送HTTP请求;
5.获取异步调用返回的数据;
6.使用JavaScript和DOM实现局部刷新.

1、var xhr = new XMLHttpRequest(); // 创建xhr对象
2、xhr.open('GET', 'example.php');
3、xhr.onreadystatechange = function(){
  if ( xhr.readyState == 4 && xhr.status == 200 ) {
     alert( xhr.responseText );
  } else {
     alert( xhr.statusText );
  }
};
xhr.setRequestHeader( ..., ... );
4、xhr.send();

readyState: unsigned short - 用于表示请求的五种状态:

clipboard.png

具体有关XMLHttpRequest内容可查看文章你不知道的 XMLHttpRequestHTTP 最强资料大全

ajax的缺点和在IE下的问题:

  1. ajax不支持浏览器back按钮。

  2. 安全问题 AJAX暴露了与服务器交互的细节。

  3. 对搜索引擎的支持比较弱。

  4. 破坏了程序的异常机制。

  5. 不容易调试。


Web Worker 和webSocket?

worker主线程:Web Worker可以分为两种不同线程类型,一个是专用线程,一个是共享线程。
使用限制:

  • Web Worker无法访问DOM节点;

  • Web Worker无法访问全局变量或是全局函数;

  • Web Worker无法调用alert()或者confirm之类的函数;

  • Web Worker无法访问window、document之类的浏览器全局变量;

专用线程示例

主线程代码

/** 1. 创建专用线程 **/
var worker = new Worker('dedicated.js');
/** 2. 接收来至工作线程 **/
worker.onmessage = function (event) { ... };
/** 3.发送 ArrayBuffer 数据代码 **/
worker.postMessage(10000);
/** 4.终止一个worker的执行 **/
worker.terminate();

------------------------------------------------

worker线程代码

addEventListener("message", function(evt){  
var date = new Date();  
var currentDate = null;  
do {  
    currentDate = new Date();  
}while(currentDate - date < evt.data);  
    postMessage(currentDate);  
}, false);  

共享线程示例:

/** 1. 创建共享线程 **/
var worker = new SharedWorker('sharedworker.js', ’ mysharedworker ’ );
/** 2. 从端口接收数据 , 包括文本数据以及结构化数据 **/
worker.port.onmessage = function (event) { define your logic here... }; 
/** 3. 向端口发送普通文本数据 **/
 worker.port.postMessage('put your message here … '); 
/** 向端口发送结构化数据 **/
worker.port.postMessage({ username: 'usertext'; live_city: 
['data-one', 'data-two', 'data-three','data-four']});

socket:Websocket 其实是基于 HTML5 规范的一个新协议,它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯,它建立在 TCP 之上,同 HTTP 一样通过 TCP 来传输数据。

  • WebSocket 是一种双向通信协议,在建立连接后,WebSocket 服务器和 Browser/Client Agent 都能主动的向对方发送或接收数据,就像 Socket 一样;

  • WebSocket 需要类似 TCP 的客户端和服务器端通过握手连接,连接成功后才能相互通信。

HTTP请求与响应交互图:

clipboard.png

WebSocket请求与响应交互图:

clipboard.png

相对于传统 HTTP 每次请求-应答都需要客户端与服务端建立连接的模式,WebSocket 是类似 Socket 的 TCP 长连接的通讯模式,一旦 WebSocket 连接建立后,后续数据都以帧序列的形式传输。在客户端断开 WebSocket 连接或 Server 端断掉连接前,不需要客户端和服务端重新发起连接请求。在海量并发及客户端与服务器交互负载流量大的情况下,极大的节省了网络带宽资源的消耗,有明显的性能优势,且客户端发送和接受消息是在同一个持久连接上发起,实时性优势明显。

WebSocket 通讯请求响应报文:
客户端连接报文:

clipboard.png

可以看到,客户端发起的 WebSocket 连接报文类似传统 HTTP 报文,'Upgrade:websocket'参数值表明这是 WebSocket 类型请求,“Sec-WebSocket-Key”是 WebSocket 客户端发送的一个 base64 编码的密文,要求服务端必须返回一个对应加密的“Sec-WebSocket-Accept”应答,否则客户端会抛出“Error during WebSocket handshake”错误,并关闭连接。

服务端响应报文:

clipboard.png

Sec-WebSocket-Accept”的值是服务端采用与客户端一致的密钥计算出来后返回客户端的。,“HTTP/1.1 101 Switching Protocols”表示服务端接受 WebSocket 协议的客户端连接,经过这样的请求-响应处理后,客户端服务端的 WebSocket 连接握手成功, 后续就可以进行 TCP 通讯了。

WebSocket 实现
支持浏览器:

clipboard.png

实现代码:

/** 申请一个WebSocket对象,参数为需要连接的服务端地址,协议的URL使用ws://开头,安全的WebSocket协议使用wss://开头 **/
var ws = new WebSocket('ws://...');

/** 当 Browser 和 WebSocketServer 连接成功后,会触发 onopen 消息 **/
ws.onopen = function(){ws.send(“Test!”);};

/** 如果连接失败,发送、接收数据失败或者处理数据出现错误,browser 会触发 onerror 消息 **/
ws.onerror = function(evt){console.log('error')};

/** 当 Browser 接收到 WebSocketServer 发送过来的数据时,就会触发 onmessage 消息,参数 evt 中包含 Server 传输过来的数据 **/
ws.onmessage = function(evt){console.log(evt.data);ws.close();}; 

/** 当 Browser 接收到 WebSocketServer 端发送的关闭连接请求时,就会触发 onclose 消息 **/
 ws.onclose = function(evt){console.log(“WebSocketClosed!”);}; 

所有的操作都是采用异步回调的方式触发,这样不会阻塞 UI,可以获得更快的响应时间,更好的用户体验。

谈谈对HTTP的理解?

http中文叫超文本传输协议,是客户端与服务端之间传输数据规定的一种协议,通常承载与TCP协议之上,基于请求与响应模式的、无状态的、应用层的协议,常基于TCP的连接方式。
特点:

  • 支持客户/服务器模式;

  • 简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快;

  • 灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记;

  • 无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。

  • 无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。在实际应用当中并不是完全这样的,引入了Cookie和Session机制来关联请求。

HTTP报文:
请求报文:由请求行请求头请求体构成,每一行的末尾都有回车和换行,在请求头和请求体之间还有一个空行

  1. 请求行指定由请求方法请求URL协议版本组成;

  2. 请求头是由键值对形式存在的,例如content-type:application/json;

  3. 空行;

  4. 请求体就是要传输的数据;

clipboard.png

响应报文:由状态行响应头响应体组成。

  1. 状态行由协议版本状态码状态短语组成;

  2. 响应头也是由键值对形式存在,例如:
    Content-Length: 563
    Content-Type: text/html

  3. 空行;

  4. 响应体即要传输的数据;

clipboard.png

HTTP请求方法

  1. GET:获取资源;

  2. POST:传输实体主体; POST方法用来传输实体主体。POST与GET的区别之一就是目的不同,二者之间的区别会在文章的最后详细说明。虽然GET方法也可以传输,但是一般不用,因为GET的目的是获取,POST的目的是传输。

  3. PUT:传输文件; PUT方法用来传输文件。类似FTP协议,文件内容包含在请求报文的实体中,然后请求保存到URL指定的服务器位置。

  4. HEAD:获得报文首部; HEAD方法类似GET方法,但是不同的是HEAD方法不要求返回数据。用于确认URI的有效性及资源更新时间等。

  5. DELETE:删除文件; DELETE方法用来删除文件,是与PUT相反的方法。DELETE是要求返回URL指定的资源。

  6. OPTIONS:询问支持的方法; 因为并不是所有的服务器都支持规定的方法,为了安全有些服务器可能会禁止掉一些方法例如DELETE、PUT等。那么OPTIONS就是用来询问服务器支持的方法。

  7. TRACE:追踪路径; TRACE方法是让Web服务器将之前的请求通信还回给客户端的方法。这个方法并不常用。

  8. CONNECT:要求用隧道协议连接代理; CONNECT方法要求在与代理服务器通信时建立隧道,实现用隧道协议进行TCP通信。主要使用SSL/TLS协议对通信内容加密后传输。

clipboard.png

HTTP的响应状态码:

clipboard.png

get和post区别:

  1. get请求数据会附加在url之后,以?分割url地址和传输数据,多个参数用&链接。传输数据会受到url长度的限制。并且get请求由于把请求数据都放在URL上,这样很容易被他人拿到数据。比如登录页面,用户名和密码都会暴露在URL上。

  2. post请求会把数据放在请求实体中,这样理论上是没有大小限制,并且POST可能会修改服务器上的资源的请求。

常用状态码:

  1. 200:OK;
    代表请求被正常的处理成功了。

  2. 204:No Content;
    请求处理成功,但是没有数据实体返回,也不允许有实体返回。比如说HEAD请求,可能就会返回204 No Content,因为HEAD就是只获取头信息。

  3. 205:Reset Content;
    不但没有数据实体返回,而且还需要重置表单,方便用户再次输入。

  4. 206:Partial Content;
    这是客户端使用Content-Range指定了需要的实体数据的范围,然后服务端处理请求成功之后返回用户需要的这一部分数据而不是全部,执行的请求就是GET。

  5. 301:Moved Permanently;
    代表永久性定向。该状态码表示请求的资源已经被分配了新的URL,以后应该使用资源现在指定的URL。也就是说如果已经把资源对应的URL保存为书签了,这是应该按照Location首部字段提示的URL重新保存。

  6. 302:Found;
    代表临时重定向。该状态码表示请求的资源已经被分配了新的URL,但是和301的区别是302代表的不是永久性的移动,只是临时的。就是说这个URL还可能会发生改变。如果保存成书签了也不会更新。

  7. 303:See Other;
    和302的区别是303明确规定客户端应当使用GET方法。

  8. 304:Not Modified;
    该状态码表示客户端发送附带条件请求时,服务器端允许请求访问资源,但是没有满足条件,浏览器在接收到个状态码后,会使用浏览器已缓存的文件。304状态码返回时不包含任何数据实体。304虽然被划分在3XX中但是和重定向没有关系。

客户端请求一个页面(A)。 服务器返回页面A,并在给A加上一个ETag。 客户端展现该页面,并将页面连同ETag一起缓存。
客户再次请求页面A,并将上次请求时服务器返回的ETag一起传递给服务器。
服务器检查该ETag,并判断出该页面自上次客户端请求之后还未被修改,直接返回响应304(未修改——Not
Modified)和一个空的响应体。

  1. 307:Temporary Redirect;
    临时重定向,与302 Found相同,但是302会把POST改成GET,而307就不会。

  2. 400:Bad Request;
    400表示请求报文中存在语法错误。需要修改后再次发送。

  3. 401:Unauthorized;
    该状态码表示未授权,请求要求身份验证。对于登录后请求的网页,服务器可能返回此响应。

  4. 403:Forbidden;
    表明请求访问的资源被拒绝了。没有获得服务器的访问权限,IP被禁止等。

  5. 404:Not Found;
    表明请求的资源在服务器上找不到。当然也可以在服务器拒绝请求且不想说明理由时使用。

  6. 408:Request Timeout;
    表示客户端请求超时,就是在客户端和服务器建立连接后服务器在一定时间内没有收到客户端的请求。

  7. 500:Internal Server Error;
    表明服务器端在执行请求时发生了错误,很有可能是服务端程序的Bug或者临时故障。

  8. 503:Service Unavailable;
    表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。如果事先得知解除以上状况需要的时间,最好写入Retry-After字段再返回给客户端。

  9. 504:Getaway Timeout;
    网关超时,是代理服务器等待应用服务器响应时的超时,和408 Request Timeout的却别就是504是服务器的原因而不是客户端的原因。


HTTP和HTTPS区别?

HTTP协议通常承载于TCP协议之上,在HTTP和TCP之间添加一个安全协议层(SSL或TSL),这个时候,就成了我们常说的HTTPS。
默认HTTP的端口号为80,HTTPS的端口号为443。

为什么HTTPS安全?
因为网络请求需要中间有很多的服务器路由器的转发。中间的节点都可能篡改信息,而如果使用HTTPS,密钥在你和终点站才有。https之所以比http安全,是因为他利用ssl/tls协议传输。它包含证书,卸载,流量转发,负载均衡,页面适配,浏览器适配,refer传递等,保障了传输过程的安全性。


浏览器地址栏输入一个URL回车后,发生了什么?

  1. 浏览器通过DNS查询查找出域名的IP地址:浏览器缓存 >> 系统缓存 >> 路由器缓存 >> ISP DNS 缓存 >> 递归搜索

  2. 通过TCP三次握手与服务器建立连接;

  3. 浏览器发送http请求报文;

  4. 服务器返回http响应报文;

  5. 断开TCP连接;

  6. 浏览器解析HTML/SVG/XHTML,解析这三种文件产生一个 DOM Tree;

  7. 在浏览器显示HTML时,它会注意到需要获取其他地址内容的标签。这时,浏览器会发送一个获取请求来重新获得这些文件。这些文件就包括CSS/JS/图片等资源,这些资源的地址都要经历一个和HTML读取类似的过程。所以浏览器会在DNS中查找这些域名,发送请求,重定向等等…;

  8. 浏览器解析 CSS 会产生 CSS 规则树;

  9. 解析JavaScript脚本,主要是通过 DOM API 和 CSSOM API 来操作 DOM Tree 和 CSS Rule Tree

浏览器解析渲染过程是逐步完成的,为了更好的用户体验,渲染引擎将会尽可能早的将内容呈现到屏幕上,并不会等到所有的html都解析完成之后再去构建和布局render树。它是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容。

  1. Reflow(回流):浏览器要花时间去渲染,当它发现了某个部分发生了变化影响了布局,那就需要倒回去重新渲染。

  2. Repaint(重绘):如果只是改变了某个元素的背景颜色,文字颜色等,不影响元素周围或内部布局的属性,将只会引起浏览器的repaint,重画某一部分。

clipboard.png

编写CSS注意事项:
CSS选择符是从右到左进行匹配的。#nav li 会去找所有的li,然后再去确定它的父元素是不是#nav。

  1. dom深度尽量浅;

  2. 减少inline javascript、css的数量;

  3. 使用现代合法的css属性;

  4. 不要为id选择器指定类名或是标签,因为id可以唯一确定一个元素;

  5. 避免后代选择符,尽量使用子选择符。原因:子元素匹配符的概率要大于后代元素匹配符。后代选择符;#tp p{} 子选择符:#tp>p{};

  6. 避免使用通配符,举一个例子,.mod .hd *{font-size:14px;} 根据匹配顺序,将首先匹配通配符,也就是说先匹配出通配符,然后匹配.hd(就是要对dom树上的所有节点进行遍历他的父级元素),然后匹配.mod,这样的性能耗费可想而知.

script标签为什么要放在body结束标签之前?

因为js的下载和执行会阻塞Dom树的构建。

  1. 载入后马上执行;

  2. 执行时会阻塞页面后续的内容(包括页面的渲染、其它资源的下载)。原因:因为浏览器需要一个稳定的DOM树结构,而JS中很有可能有 代码直接改变了DOM树结构,比如使用 document.write 或appendChild,甚至是直接使用的location.href进行跳转,浏览器为了防止出现JS修改DOM树,需要重新构建DOM树的情况,所以 就会阻塞其他的下载和呈现。

减少 JavaScript 对性能的影响的方法:

  1. 将所有的script标签放到页面底部,也就是body闭合标签之前,这能确保在脚本执行前页面已经完成了DOM树渲染。

  2. 尽可能地合并脚本。页面中的script标签越少,加载也就越快,响应也越迅速。无论是外链脚本还是内嵌脚本都是如此。

  3. 采用无阻塞下载 JavaScript 脚本的方法:
    (1)、使用script标签的 defer 属性(仅适用于 IE 和 Firefox 3.5 以上版本);
    (2)、使用动态创建的script元素来下载并执行代码;
    (3)、按需异步载入js;

Cookie、sessionStorage、localStorage的区别?

SessionStorage 和 localStorage 是HTML5 storage API 提供的, 可以把数据保存在本地,避免了数据在浏览器和服务器之间不必要的通信。sessionStorage,localStorage, cookie 都是在浏览器存储的数据。

不同:

  1. cookie数据始终在同源http中携带,即使不需要,也会在浏览器和服务器间来回传递。Storage只存在本地;

  2. cookie数据有路径概念,可以限制cookie只能在某路径下;

  3. cookie:4k Storage:5M;

  4. sessionStorage: 仅在当前浏览器关闭前有效,localStorage:始终有效,cookie:过期之前有效;

  5. sessionStorage:在打开的不同浏览器窗口不共享,即使同一页面,localStorage:在同源页面共享,cookie:同源页面共享

待续.....2017.5.31


永久
69 声望3 粉丝