# 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')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  1. 使用XHR对象时,要调用第一个方法是open(),接收三个参数:要发送的请求类型,请求的URL,是否异步发送请求的布尔值。调用open()方法不会真正的发送请求,而只是启动一个请求以备发送。
  2. send()方法接收一个参数,即要作为请求主体发送的数据。如果不需要则传入null
  3. responseText:作为响应主体被返回的文本。
  4. responseXML:如果响应内容类型是text/xmlapplication/xml,这个属性中将保存包含着响应数据的XML DOM文档
  5. status: 响应的HTTP状态。
  6. statusTextHTTP状态的说明。

多数情况下我们要发送异步请求,才能让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)
1
2
3
4
5
6
7
8
9
10
11
12

TIP

  1. 使用post方式发送数据时,在调用send方法时,需要设置请求的MIME类型
  • application/x-www-form-urlencoded:提交的数据按照 key1=val1&key2=val2 的方式进行编码,keyval 会进行了 URL 转码
xhr.setRequestHeader(
    'Content-Type',
    'application/x-www-form-urlencoded'
)
1
2
3
4
  • multipart/form-data表单上传文件
  • application/json
  • text/xml

我们现在一般这样来使用:

  • XML 存储数据,存储配置文件等需要结构化存储的地方使用;
  • 数据传输、数据交互使用JSON
  1. 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') 
1
2

# Ajax的优缺点

TIP

  • 优点:

    • 页面无刷新,在页面内与服务器通信,减少用户等待时间,增强了用户体验。
    • 使用异步方式与服务器通信,响应速度更快。
    • 可以把一些原本服务器的工作转接到客户端,利用客户端闲置的能力来处理,减轻了服务器和带宽的负担,节约空间和宽带租用成本。
    • 基于标准化的并被广泛支持的技术,不需要下载插件或者小程序。
  • 缺点:

    • 无法进行操作的后退,即不支持浏览器的页面后退。
    • 对搜索引擎的支持比较弱。
    • 可能会影响程序中的异常处理机制。
    • 安全问题,对一些网站攻击,如csrf、xxs、sql注入等不能很好地防御。

# jquery中的Ajax请求

  1. $.ajax()返回其创建的 XMLHttpRequest 对象。
$.ajax({
    type: 'post',
    dataType: 'html',
    url: '/Resource/GetList.ashx',
    data: dataurl,
    success: function(data) {
        console.log(data)
    }
})
1
2
3
4
5
6
7
8
9
  1. 通过远程 HTTP GET 请求载入信息。

相比于复杂的$.ajax而言,GET请求功能则显得更加简单,请求成功时可调用回调函数。当然如果需要在出错时执行函数,那么还请使用$.ajax

$.get('test.cgi',{name: 'john'},function(data) {
    console.log(data)
})
1
2
3
  1. 通过远程 HTTP POST 请求载入信息。
$.post('test.cgi',{name: 'john'},function(data) {
    console.log(data)
})
1
2
3
  1. 通过 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;
    });
});
1
2
3
4
5
6

# HTTP头部信息

发送请求时,请求头部信息

  • Accept:浏览器能够处理的内容类型
  • Accept-Charset:浏览器能够显示的字符集
  • Accept-Encoding:浏览器能够处理的压缩编码
  • Accept-Language:浏览器当前设置的语言
  • Connection:浏览器与服务器之间连接的类型
  • Cookie:当前页面设置的任何Cookie
  • Host:发出请求的页面所在域
  • 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 协议没有 BodyURL 的长度限制,对 URL 限制的大多是浏览器和服务器的原因。服务器是因为处理长 URL 要消耗比较多的资源,为了性能和安全(防止恶意构造长URL 来攻击)考虑,会给 URL 长度加限制。URL这种东西必须当作一个整体看待,无法一块一块处理,于是就处理一个请求时必须分配一整块足够大的内存。如果URL太长,而并发又很高,就容易挤爆服务器的内存;

TIP

GETPOST本质上两者没有任何区别。他们都是HTTP协议中的请求方法。底层实现都是基于TCP/IP协议。上述的所谓区别,只是浏览器厂家根据约定,做得限制而已。HTTP请求,最初设定了八种方法。这八种方法本质上没有任何区别。只是让请求,更加有语义而已。

  • 浏览器使用的GET/POST:指浏览器中非ajaxhttp请求。浏览器用GET请求来获取一个html页面/图片等资源;用POST来提交一个<form>表单,并得到一个结果的网页。

    • 因为GET因为是读取,就可以对GET请求的数据做缓存。这个缓存可以做到浏览器本身上(彻底避免浏览器发请求),也可以做到代理上(如nginx),或者做到server端(用Etag,至少可以减少带宽消耗)
    • 在页面里<form> 标签会定义一个表单。点击其中的submit元素会发出一个POST请求让服务器做一件事。这件事往往是有副作用的,不幂等的。所以浏览器实现为不能把POST请求保存为书签
    • 当浏览器发出一个GET请求时,就意味着要么是用户自己在浏览器的地址栏输入,要不就是点击了htmla标签的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" >里的urlquerystring就行。只不过表单里面的那些用<input> 等标签经过用户操作产生的数据都在会在body里。我们一般会泛泛的说“GET请求没有body,只有url,请求数据放在urlquerystring中;POST请求的数据在body中。但这种情况仅限于浏览器发请求的场景。
  • ajax中的get/post

    • 对于请求例如几百兆压缩二进制流的请求体,服务器端接收到请求后,就可以先拿到请求头部,查看用户是不是有权限上传,文件名是不是符合规范等。如果不符合,就不再处理请求体的数据了,直接丢弃。为了进一步优化,客户端可以利用HTTPContinued协议来这样做:客户端总是先发送所有请求头给服务器,让服务器校验。如果通过了,服务器回复“100 - Continue”,客户端再把剩下的数据发给服务器。如果请求被拒了,服务器就回复个400之类的错误,这个交互就终止了。所以就会误认为POST需要发送两个请求。
    • 对于GET方式的请求,浏览器会把http headerdata一并发送出去,服务器响应200(返回数据);
  • 幂等(意思是多次执⾏相同的操作,结果都是「相同」的)

    • GET ⽅法就是安全且幂等的,因为它是「只读」操作,⽆论操作多少次,服务器上的数据都是安全的,且每次的结果都是相同的。
    • POST 因为是「新增或提交数据」的操作,会修改服务器上的资源,所以是不安全的,且多次提交数据就会创建多个资源,所以不是幂等的。

# FormData

XMLHttpRequest 2级定义了该类型,为序列化表单以及创建与表单格式相同的数据提供便利

var data = new FormData()
data.append('name','Nicholas')
1
2

使用FormData的方便之处体现在不必明确地在XHR对象上设置请求头部。XHR对象能够识别传入的数据类型是FormData的实例,并配置合适的头部信息。