# ajax原生
JavaScript执行异步网络请求,有了Ajax之后,就可以实现在网页不跳转不刷新的情况下,在网页后台提交数据,部分更新页面内容。核心是XMLHttpRequest对象。
# 实现流程
- 创建
XMLHttpRequest对象 - 打开请求地址,初始化数据
 - 发送请求数据
 - 监听回调函数状态
 - 收到服务器返回的应答结果
 
var xmlhttp;
function loadXMLDoc(url) {
    xmlhttp = null;
    if(window.XMLHttpRequest) {
        xmlhttp = new XMLHttpRequest()
    } else if(window.ActiveXObject) {
        xmlhttp = new ActiveXObject('Microsoft.XMLHTTP')
    }
    if(xmlhttp != null) {
        xmlhttp.open('GET', url, true); // true默认异步,表示该脚本会在send()方法之后继续执行,而不等待来自服务器的响应。
        xmlhttp.send(null)
        xmlhttp.onreadystatechange = state_Change;
    } else {
        alert('Your browser does not support XMLHTTP')
    }
    function state_Change() {
        if(xmlhttp.readyState==4&&xmlhttp.status ==200) {
            var data = xmlhttp.responseText
            console.log(data)
        } else {
            alert("Problem retrieving XML data")
        }
    }
}
loadXMLDoc('http://iconcool.kingdee.com/index/mix')
 2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
- 使用
XHR对象时,要调用第一个方法是open(),接收三个参数:要发送的请求类型,请求的URL,是否异步发送请求的布尔值。调用open()方法不会真正的发送请求,而只是启动一个请求以备发送。 send()方法接收一个参数,即要作为请求主体发送的数据。如果不需要则传入nullresponseText:作为响应主体被返回的文本。responseXML:如果响应内容类型是text/xml或application/xml,这个属性中将保存包含着响应数据的XML DOM文档status: 响应的HTTP状态。statusText:HTTP状态的说明。
多数情况下我们要发送异步请求,才能让Javascript继续执行而不必等待响应。此时可以检测XHR对象的readyState属性,该属性表示请求/响应过程的当前活动阶段。取值情况:
- 0:未初始化。尚未调用
open()方法 - 1:启动,已经调用
open()方法,但尚未调用send()方法 - 2:发送,已经调用
send()方法,但尚未接收到响应 - 3:接收:已经接收到部分响应数据
 - 4:完成:已经接收到全部数据,而且已经在客户端中使用。
 
只要readyState属性的值由一个值变成另一个值,都会触发一次readystatechange事件。不过在调用open()之前指定onreadystatechange事件处理程序才能确保跨浏览器兼容性。
var xhr = createXHR();
xhr.onreadystatechange = function() {
    if(xhr.readyState == 4) {
        if(xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 {
            alert(xhr.responseText)
        } else {
            alert("Response was unsuccessful:" + xhr.status)
        }
    }
}
xhr.open('get', 'example.txt', true)
xhr.send(null)
 2
3
4
5
6
7
8
9
10
11
12
TIP
- 使用
post方式发送数据时,在调用send方法时,需要设置请求的MIME类型 
application/x-www-form-urlencoded:提交的数据按照key1=val1&key2=val2的方式进行编码,key和val会进行了URL转码
xhr.setRequestHeader(
    'Content-Type',
    'application/x-www-form-urlencoded'
)
 2
3
4
multipart/form-data表单上传文件application/jsontext/xml
我们现在一般这样来使用:
XML存储数据,存储配置文件等需要结构化存储的地方使用;- 数据传输、数据交互使用
JSON; 
get/post在ajax请求中传参的差异:
- 我们要在发送
get请求时携带数据,只需要在调用open()方法时,将数据写在第二个参数的URL的?后面即可 - 发送
post请求的过程几乎和get请求一样,唯一不一样的是数据的传递。大家都知道post请求的数据是放在请求体中的,因此我们需要调用xhr对象上的setRequestHeader()方法来模仿表单提交时的内容类型 
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
xhr.send('query=4&em=0') 
 2
# Ajax的优缺点
TIP
优点:
- 页面无刷新,在页面内与服务器通信,减少用户等待时间,增强了用户体验。
 - 使用异步方式与服务器通信,响应速度更快。
 - 可以把一些原本服务器的工作转接到客户端,利用客户端闲置的能力来处理,减轻了服务器和带宽的负担,节约空间和宽带租用成本。
 - 基于标准化的并被广泛支持的技术,不需要下载插件或者小程序。
 
缺点:
- 无法进行操作的后退,即不支持浏览器的页面后退。
 - 对搜索引擎的支持比较弱。
 - 可能会影响程序中的异常处理机制。
 - 安全问题,对一些网站攻击,如
csrf、xxs、sql注入等不能很好地防御。 
# jquery中的Ajax请求
$.ajax()返回其创建的XMLHttpRequest对象。
$.ajax({
    type: 'post',
    dataType: 'html',
    url: '/Resource/GetList.ashx',
    data: dataurl,
    success: function(data) {
        console.log(data)
    }
})
 2
3
4
5
6
7
8
9
- 通过远程 
HTTP GET请求载入信息。 
相比于复杂的
$.ajax而言,GET请求功能则显得更加简单,请求成功时可调用回调函数。当然如果需要在出错时执行函数,那么还请使用$.ajax。
$.get('test.cgi',{name: 'john'},function(data) {
    console.log(data)
})
 2
3
- 通过远程 
HTTP POST请求载入信息。 
$.post('test.cgi',{name: 'john'},function(data) {
    console.log(data)
})
 2
3
- 通过 
HTTP GET请求载入JSON数据。 
$.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=?",function(data){
    $.each(data.items, function(i,item){
        $("<img/>").attr("src", item.media.m).appendTo("#images");
        if ( i == 3 ) return false;
    });
});
 2
3
4
5
6
# HTTP头部信息
 发送请求时,请求头部信息
Accept:浏览器能够处理的内容类型Accept-Charset:浏览器能够显示的字符集Accept-Encoding:浏览器能够处理的压缩编码Accept-Language:浏览器当前设置的语言Connection:浏览器与服务器之间连接的类型Cookie:当前页面设置的任何CookieHost:发出请求的页面所在域Referer:发出请求的页面的URL(一个拼错的字段,应该为referrer)User-Agent:浏览器的用户代理字符串
使用setRequestHeader()方法可以设置自定义的请求头部信息。接收头部字段和头部字段的值两个参数。要成功发送请求头部信息,必须在调用open()方法之后且调用send()方法之前调用该方法。服务端接收到这种自定义的头部信息之后,可以执行相应的后续操作。调用XHR对象的getResponseHeader()方法并传入头部字段名称,可以取得相应的响应头部信息。而调用getAllResponseHeaders()方法则可以取得一个包含搜友头部信息的长字符串。
# GET/POST
 GET- 可以将查询字符串参数追加到
URL末尾,以便将信息发送给服务器。查询字符串每个参数的名称和值都必须使用encodeURIComponent进行编码才能放到URL末尾。 
- 可以将查询字符串参数追加到
 POST- 参数放在
body中 
- 参数放在
 
TIP
POST方法更安全? 从传输的角度来说,他们都是不安全的,因为HTTP在网络上是明文传输的,只要在网络节点上捉包,就能完整地获取数据报文。要想安全传输,就只有加密,也就是HTTPS。只要记得一般情况下,私密数据传输用POST + body就好。
GET参数,浏览器地址栏输入参数长度限制HTTP协议没有Body和URL的长度限制,对URL限制的大多是浏览器和服务器的原因。服务器是因为处理长URL要消耗比较多的资源,为了性能和安全(防止恶意构造长URL来攻击)考虑,会给URL长度加限制。URL这种东西必须当作一个整体看待,无法一块一块处理,于是就处理一个请求时必须分配一整块足够大的内存。如果URL太长,而并发又很高,就容易挤爆服务器的内存;
TIP
GET和POST本质上两者没有任何区别。他们都是HTTP协议中的请求方法。底层实现都是基于TCP/IP协议。上述的所谓区别,只是浏览器厂家根据约定,做得限制而已。HTTP请求,最初设定了八种方法。这八种方法本质上没有任何区别。只是让请求,更加有语义而已。
浏览器使用的
GET/POST:指浏览器中非ajax的http请求。浏览器用GET请求来获取一个html页面/图片等资源;用POST来提交一个<form>表单,并得到一个结果的网页。- 因为
GET因为是读取,就可以对GET请求的数据做缓存。这个缓存可以做到浏览器本身上(彻底避免浏览器发请求),也可以做到代理上(如nginx),或者做到server端(用Etag,至少可以减少带宽消耗) - 在页面里
<form>标签会定义一个表单。点击其中的submit元素会发出一个POST请求让服务器做一件事。这件事往往是有副作用的,不幂等的。所以浏览器实现为不能把POST请求保存为书签 - 当浏览器发出一个
GET请求时,就意味着要么是用户自己在浏览器的地址栏输入,要不就是点击了html里a标签的href中的url。所以其实并不是GET只能用url,而是浏览器直接发出的GET只能由一个url触发。所以没办法,GET上要在url之外带一些参数就只能依靠url上附带querystring。但是HTTP协议本身并没有这个限制。 - 浏览器的
POST请求都来自表单提交。每次提交,表单的数据被浏览器用编码到HTTP请求的body里。浏览器发出的POST请求的body主要有有两种格式,一种是application/x-www-form-urlencoded用来传输简单的数据,大概就是"key1=value1&key2=value2"这样的格式。另外一种是传文件,会采用multipart/form-data格式。采用后者是因为application/x-www-form-urlencoded的编码方式对于文件这种二进制的数据非常低效。 - 浏览器在
POST一个表单时,url上也可以带参数,只要<form action="url" >里的url带querystring就行。只不过表单里面的那些用<input>等标签经过用户操作产生的数据都在会在body里。我们一般会泛泛的说“GET请求没有body,只有url,请求数据放在url的querystring中;POST请求的数据在body中。但这种情况仅限于浏览器发请求的场景。 
- 因为
 ajax中的get/post- 对于请求例如几百兆压缩二进制流的请求体,服务器端接收到请求后,就可以先拿到请求头部,查看用户是不是有权限上传,文件名是不是符合规范等。如果不符合,就不再处理请求体的数据了,直接丢弃。为了进一步优化,客户端可以利用
HTTP的Continued协议来这样做:客户端总是先发送所有请求头给服务器,让服务器校验。如果通过了,服务器回复“100 - Continue”,客户端再把剩下的数据发给服务器。如果请求被拒了,服务器就回复个400之类的错误,这个交互就终止了。所以就会误认为POST需要发送两个请求。 - 对于
GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据); 
- 对于请求例如几百兆压缩二进制流的请求体,服务器端接收到请求后,就可以先拿到请求头部,查看用户是不是有权限上传,文件名是不是符合规范等。如果不符合,就不再处理请求体的数据了,直接丢弃。为了进一步优化,客户端可以利用
 幂等(意思是多次执⾏相同的操作,结果都是「相同」的)
GET⽅法就是安全且幂等的,因为它是「只读」操作,⽆论操作多少次,服务器上的数据都是安全的,且每次的结果都是相同的。POST因为是「新增或提交数据」的操作,会修改服务器上的资源,所以是不安全的,且多次提交数据就会创建多个资源,所以不是幂等的。
# FormData
 XMLHttpRequest 2级定义了该类型,为序列化表单以及创建与表单格式相同的数据提供便利
var data = new FormData()
data.append('name','Nicholas')
 2
使用FormData的方便之处体现在不必明确地在XHR对象上设置请求头部。XHR对象能够识别传入的数据类型是FormData的实例,并配置合适的头部信息。