JavaScript笔记(AJAX 与 JSONP)

1 AJAX

Asynchronous Javascript and XML(异步传输 JavaScript和XML),简单来说就是:JS调用异步通讯组件并使用格式化的数据(包括XML,JSON)来更新web页面上的内容或操作过程,而这个方法就算是AJAX。

有很多时候,一些网站点击一个按钮提交一次HTTP请求,整个网页都会自动刷新,尽管新网页可能只有一行字不同,这是因为一个HTML请求只能对应一个页面,如果想不刷新页面发送HTTP请求,就需要JS自身发送HTTP请求,接受到数据后,再用JS更新页面内容。

1.2 编写AJAX

参考网站:
w3c关于XMLHttpResquest
w3c关于XMLHttpResquest.2

在现代浏览器上写AJAX主要依靠XMLHttpRequest对象,什么是XMLHttpRequest对象
XMLHttpRequest 对象用于在后台与服务器交换数据,它充当着浏览器总的脚本与服务器之间的中间人角色,使用它能够做到:

  • 在不重新加载页面的情况下更新网页
  • 在页面已加载后从服务器请求数据
  • 在页面已加载后从服务器接收数据
  • 在后台向服务器发送数据

创建XMLHttpRequest对象并不复杂,但是由于AJAX请求是异步执行的,也就是说,还要通过制作回调函数获得响应事件。
XMLHttpRequest对象有三个重要的属性分别是:

  • readyState属性:当一个XMLHttpRequest对象初次创建时,readyState属性为0,如果收到完整的HTTP响应,属性值就会变为4:
    • 0:初始化状态
    • 1:服务器连接已建立(open()方法已调用,但是send()方法未调用)
    • 2:请求已接收(Send() 方法已调用,HTTP 请求已发送到 Web 服务器)
    • 3:请求处理中(所有响应头部都已经接收到。响应体开始接收但未完成)
    • 4:HTTP 响应已经完全接收
  • status属性:服务器返回的 HTTP 状态代码,如 200 表示成功,而 404 表示 “Not Found” 错误
  • onreadystatechange事件属性,用来存储函数,每当readyState属性有改变,就会触发存储的函数。
    仅当stats等于200且readystate等于4时,表示响应已就绪。
    列举几个XMLHttpResquest对象常用到方法:

  • open()初始化 HTTP 请求参数,XMLHttpResquest对象方法有很多,最有用的是open方法。它有三个参数:一指定服务器上将要访问的目标文件即URL;二指定请求类型如GET等;三是一个布尔值,用来定义是否使用异步。

  • setRequestHeader():设置头部信息,如通常的创建POST方法,需要定义Content-Type,也就是使用这个接口定义的了。
  • send()发送 HTTP 请求,使用传递给 open() 方法的参数,以及传递给该方法的可选请求体。
  • responseText: 获得字符串形式的响应数据
  • responseXML:获得 XML 形式的响应数据
/* 创建响应时需要用到的函数 */
function success(text) {
    var textarea = document.getElementById('test-response-text');
    textarea.value = text;
}

/*
大概步骤分为:
使用open()指定请求目标;
确定响应函数(onreadystatechange);
使用send()发送请求;
*/

function fail(code) {
    var textarea = document.getElementById('test-response-text');
    textarea.value = 'Error code: ' + code;
}

var request = new XMLHttpRequest(); // 新建XMLHttpRequest对象

request.onreadystatechange = function () { // 状态发生变化时,函数被回调,注意参数是函数,而不是直接调用函数
    if (request.readyState === 4) { // 成功完成
        // 判断响应结果:
        if (request.status === 200) {
            // 成功,通过responseText拿到响应的文本:
            return success(request.responseText);
        } else {
            // 失败,根据响应码判断失败原因:
            return fail(request.status);
        }
    } else {
        // HTTP请求还在继续...
    }
}

// 发送请求:
request.open('POST', '/api/categories');
request.setRequsetHeader("Content-Type","application/json"//"application/x-www-form-urlencoded"
var data = JSON.stringify(data);
request.send(data);

alert('请求已发送,请等待响应...');

对于低版本的IE,需要换一个ActiveXObject对象,用法都一样,通过检测window对象是否有XMLHttpRequest属性来确定浏览器是否支持标准的XMLHttpRequest,eg:

var request;
if (window.XMLHttpRequest) {
    request = new XMLHttpRequest();
} else {
    request = new ActiveXObject('Microsoft.XMLHTTP');
}
  • 因为实现异步,所以如果其他脚本都依赖服务器的响应,那么就该把相应的代码转移到指定onreadystatechange属性的那个函数上来。
  • 使用AJAX,要注意同源策略,也就是XMLHttpResquest对象发送的请求只能访问与其所在的HTML文件处于同一域的数据,即对于AJAX的open()响应url是相对路径,不能是绝对路径,即无法请求外域(就是其他网站)的URL。

另外,在拼接URL的时候还可能会使用encodeURIComponent()函数,encodeURIComponent() 函数可把字符串作为 URI 组件进行编码,如:url = encodeURIComponent(a)

2 JSONP

参考网站:
JSONP讲解

AJAX直接请求普通文件存在跨域无权限访问的问题,不过Web页面上调用外部引入的js文件时则不受是否跨域的影响(拥有src这个属性的标签都拥有跨域的能力,比如<script><img><iframe>)。
web客户端通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的js格式文件(一般以JSON为后缀),显而易见,服务器之所以要动态生成JSON文件,目的就在于把客户端需要的数据装入进去。

<html>
<head>
    <script>
        function refreshPrice(data) {
            var p = document.getElementById('test-jsonp');
            p.innerHTML = '当前价格:' +
                data['0000001'].name +':' + 
                data['0000001'].price + ';' +
                data['1399001'].name + ':' +
                data['1399001'].price;
        }
    </script>
    <script>
        function getPrice() {
            var js = document.createElement('script');
            var head = document.getElementsByTagName('head')[0];
            js.src = 'http://api.money.126.net/data/feed/0000001,1399001?callback=refreshPrice';
            head.appendChild(js);
        }
    </script>
</head>
<body>
    <p id='test-jsonp'>当前价格:</p>
    <button type="button" onclick="getPrice()">刷新</button>
</body>
</html>

讲解:当点击刷新按钮之后,会自动执行getPrice()函数,getPrice()函数的作用是在HTML文档中动态生成一个<script>脚本,该脚本调用了http://api.money.126.net/data/feed/0000001,1399001?callback=refreshPrice这个URL,调用的URL中调用了一个callback参数,这个callback参数的作用是告诉浏览器,该URL的本地回调函数叫做refreshPrice,所以请把查询结果传入这个函数中进行调用。也就是说这时会自动执行refreshPrice函数,并把服务器本身生成的json传进作为参数。

3 CORS跨域策略

参考文章:《跨域资源共享 CORS 详解》

CORS跨域策略,全称Cross-Origin Resource Sharing(HTML5),它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
CORS需要浏览器和服务器同时支持,目前,所有浏览器都支持该功能,IE浏览器不能低于IE10
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

4 设置document.domain跨域

比如,有一个页面,它的地址是http://www.example.com/a.html, 在这个页面里面有一个iframe,它的srchttp://example.com/b.html, 很显然,这个页面与它里面的iframe框架是不同域的,所以我们是无法通过在页面中书写js代码来获取iframe中的东西的,这时可以使用设置document.domain

  • 在页面http://www.example.com/a.html中设置document.domain
    ,如
<iframe src="http://example.com/b.html" id="iframe" onload='test()'></iframe>
<script>
document.domain = 'example.com'
function test () {
    alert(document.getElementById('iframe').contentWindow)
}
</script>

关于contentWindow

在页面http://example.com/b.html中也设置document.domain而且这也是必须的,虽然这个文档的domain就是example.com,但是还是必须显示的设置document.domain的值:

<script>
document.domain = 'example.com'//重复定义
</script>

5 window.postMessage(HTML5)

window.postMessage(message,targetOrigin) 方法是html5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源目前IE8+、 FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法

调用postMessage方法的window对象是指要接收消息的那一个window对象,该方法的第一个参数message为要发送的消息,类 型只能为字符串;第二个参数targetOrigin用来限定接收消息的那个window对象所在的域,如果不想限定域,可以使用通配符*

需要接收消息的window对象,可是通过监听自身的message事件来获取传过来的消息,消息内容储存在该事件对象的data属性中

<!-- a.html页面 -->
<script>
function onload () {
    var iframe = document.getElementById('iframe');
    var win = iframe.contentWindow();
    win.postMessage('来自a页面的消息''*');
}
</script>
<iframe src="http://example.com/b.html" id="iframe" onload='onload()'></iframe>

b.html页面

window.onmessage = funcation (e) { //onmessage事件
    e = e || event;
    alert(e.data) // data属性达到传送的消息
}

当然还有好几种使用外域的方法,比如

  • 通过在同源域名下架设一个代理服务器来转发,JavaScript负责把请求发送到代理服务器
  • 通过Flash插件发送HTTP请求,这种方式可以绕过浏览器的安全限制,但必须安装Flash,并且跟Flash交互。不过Flash用起来麻烦,而且现在用得也越来越少了

4 总结

Ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XMLHttpRequest对象获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本,另外jsonp是一种方式或者说非强制性协议,如同Ajax一样,它也不一定非要用json格式来传递数据。

posted @ 2017-07-17 21:05  Seiei  阅读(136)  评论(0编辑  收藏  举报