ajax(Asynchronous JavaScript + XML) 技术学习

本文进行了大致翻译。
 
Ajax 本身本不是一门技术,而是在2005年由Jesse James Garrett首创的描述为一个“新”途径来应用许多已存在的技术,包括:HTML 或者 XHTMLCascading Style SheetsJavaScriptThe Document Object ModelXMLXSLT, 和最重要的 XMLHttpRequest object
当把这些技术结合到ajax模型里的时候,web app可以快速地,逐渐地更新用户界面来取代以前的刷新整个浏览界面,这使得应用更快和用户使用体验更好。
 
尽管x在ajax里面代表xml,json由于其更轻和是javascript的一部分等优点而被更多的使用。ajax模型里面的json和xml都是用来包装数据信息的。
 

什么是AJAX?

AJAX 代表 Asynchronous JavaScript And XML. 简而言之, 他是用 XMLHttpRequestobject 来和服务器交流的方式. 它可以以不同的方式发送和接收信息, 包括 JSON, XML, HTML, 和text文件. AJAX最有吸引力的特性是 "异步", 这意味着它可以在不刷新页面的情况下同服务器交流,交换数据更新页面。
 
ajax的主要两个主要特性:
  • 不刷新页面请求数据
  • 从服务器获取数据
 

Step 1 – 如何请求

为了用javascript请求服务器,我们要实例化一个有必要功能的对象。这是XMLHttpRequest的来源。起初Internet Explorer实现了一个被称为XMLHTTP的ActiveX对象。 之后,Mozilla, Safari,和其他浏览器厂商陆续实现了XMLHttpRequest对象来支持这个方法和类似于Microsof的ActiveX对象功能。同时,Microsoft也实现了XMLHttpRequest。
 
 
// Old compatibility code, no longer needed.
if (window.XMLHttpRequest) { // Mozilla, Safari, IE7+ ...
    httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE 6 and older
    httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
 
注意:以上代码只做解释作用,只是创建了XMLHttp的实例。可以跳到step 3去看更实用的例子。
 
请求之后,我们需要接收请求结果。在这个阶段,我们需要告诉XMLHttp请求对象来处理响应的JavaScript方法,通过配置他的onreadystatechangeproperty方法,如下:
httpRequest.onreadystatechange = nameOfTheFunction;
或者
httpRequest.onreadystatechange = function(){
// Process the server response here.
};
在声明怎么接受响应之后,我们需要发起请求,通过调用HTTP请求对象的 open() 和 send() 方法,如下:
httpRequest.open('GET', 'http://www.example.org/some.file', true);
httpRequest.send();
  •  open() 的第一个参数是HTTP 请求的方法 – GET, POST, HEAD, 或者其他服务器支持的方法。方法名全部大写是http标准,不然有些浏览器(例如:Firefox)可能会不发器请求。 点击 W3C specs 获得更多关于http请求方法的信息。
  • 第二个参数是要请求的url。从安全方面考虑,默认不能跨域请求url。确保所有页面在同一个域名下,不然调用open()方法,你会得到 "permission denied” 错误。 一个常见的跨域是你网站的域名是 domain.tld,但是尝试用 www.domain.tld访问页面。如果真的想跨域请求,查看 HTTP access control
  • 可选的第三个参数设置这个请求是同步还是异步的。如果是true (默认值), JavaScript 会继续执行,用户操作页面的同时,服务器返回数据。这是 AJAX的A。
send()方法的参数可以是你想发送到服务器的任意数据(POST)。表单数据必须是服务器能解析的形式,例如查询字符串:
"name=value&anothername="+encodeURIComponent(myVar)+"&so=on"
或者其他形式,例如 multipart/form-data,JSON, XML, 等等。
注意如果你想POST数据,你可能要设置请求的MIME type。例如我们把下面代码放在调用send()之前,来把表单数据当查询数据发送:
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

Step 2 – 处理服务器响应

请求的时候,我们已经提供了处理响应的JavaScript方法:
httpRequest.onreadystatechange = nameOfTheFunction;
这个方法做什么?首先,我们需要检查请求状态。如果张台值为XMLHttpRequest.DONE (4),意味着已经接受了所有服务器的响。
if (httpRequest.readyState === XMLHttpRequest.DONE) {
// Everything is good, the response was received.
} else {
// Not ready yet.
}
 readyState 全部可能的值,可以在 XMLHTTPRequest.readyState 查看,如下:
  • 0 (uninitialized) or (请求未初始化)
  • 1 (loading) or (服务器建立连接)
  • 2 (loaded) or (请求被接收)
  • 3 (interactive) or (执行请求)
  • 4 (complete) or (request finished and response is ready请求完成响应到位)
  • Value State Description
    0 UNSENT Client has been created. open() not called yet.
    1 OPENED open() has been called.
    2 HEADERS_RECEIVED send() has been called, and headers and status are available.
    3 LOADING Downloading; responseText holds partial data.
    4 DONE The operation is complete.
接下来,检查HTTP响应的 response code 。查看 W3C看到可能的值。下面例子我们用response code是不是等于200来判断ajax请求是否成功。
if (httpRequest.status === 200) {
// Perfect!
} else {
// There was a problem with the request.
// For example, the response may have a 404 (Not Found)
// or 500 (Internal Server Error) response code.
}
检查完响应值后。我们可以随意处理服务器返回的数据,有两个选择获得这些数据:
  • httpRequest.responseText – 返回服务器响应字符串
  • httpRequest.responseXML – 返回服务器响应XMLDocument 对象 可以传递给JavaScript DOM 方法
上面的代码只有在异步的情况下有效(open() 的第三个参数设置为true)。如果你用同步请求,就没必要指定一个方法。但是我们不鼓励使用同步请求,因为同步会导致极差的用户体验。

Step 3 – 一个简单的例子

我们把上面的放在一起合成一个简单的HTTP请求。我们的JavaScript 将请求一个HTML 文档, test.html, 包含一个字符串 "I'm a test."然后我们alert()响应内容。这个例子使用普通的JavaScript — 没有引入jQuery, HTML, XML 和 PHP 文件应该放在同一级目录下。
<button id="ajaxButton" type="button">Make a request</button>

<script>
(function() {
var httpRequest;
document.getElementById("ajaxButton").addEventListener('click', makeRequest);

function makeRequest() {
httpRequest = new XMLHttpRequest();

if (!httpRequest) {
alert('Giving up :( Cannot create an XMLHTTP instance');
return false;
}
httpRequest.onreadystatechange = alertContents;
httpRequest.open('GET', 'test.html');
httpRequest.send();
}

function alertContents() {
if (httpRequest.readyState === XMLHttpRequest.DONE) {
if (httpRequest.status === 200) {
alert(httpRequest.responseText);
} else {
alert('There was a problem with the request.');
}
}
}
})();
</script>
在这个例子里:
  • 用户点击"Make a request” 按钮;
  • 事件调用 makeRequest() 方法;
  • 请求发出,然后 (onreadystatechange)执行传递给 alertContents();
  • alertContents() 检查响应是否 OK, 然后 alert() test.html 文件内容。
 
 
注意 1: 如果服务器返回XML,而不是静态XML文件,你必须设置response headers 来兼容i.e.。如果你不设置headerContent-Type: application/xml, IE 将会在你尝试获取 XML 元素之后抛出一个JavaScript "Object Expected" 错误 。
 
 
注意 2: 如果你不设置header Cache-Control: no-cache 浏览器将会缓存响应不再次提交请求,很难debug。你可以添加永远不一样的GET 参数,例如 timestamp 或者 随机数 (查看 bypassing the cache)
 
注意 3: 如果 httpRequest 变量是全局的,混杂调用 makeRequest()会覆盖各自的请求,导致一个竞争的状态。在一个closure 里声明 httpRequest 本地变量 来避免这个问题。
在发生通信错误(如服务器崩溃)、onreadystatechange方法会抛出一个异常,当访问响应状态。为了缓解这个问题,你可以用ry…catch包装你的if...then 语句:
function alertContents() {
try {
if (httpRequest.readyState === XMLHttpRequest.DONE) {
if (httpRequest.status === 200) {
alert(httpRequest.responseText);
} else {
alert('There was a problem with the request.');
}
}
}
catch( e ) {
alert('Caught Exception: ' + e.description);
}
}

Step 4 – 使用 XML 响应

在前面的例子里,在获取到响应之后,我们用request 对象responseText 属性获得 test.html 文件内容。现在让我们尝试获取responseXML 属性。
首先,让我们创建一个有效的XML文档,留着待会我们请求。(test.xml)如下:
<?xml version="1.0" ?>
<root>
I'm a test.
</root>
在这个脚本里,我们只要修改请求行为:
...
onclick="makeRequest('test.xml')">
...
然后在alertContents()里,我们需要把 alert(httpRequest.responseText); 换为:
var xmldoc = httpRequest.responseXML;
var root_node = xmldoc.getElementsByTagName('root').item(0);
alert(root_node.firstChild.data);
这里获得了responseXML的XMLDocument,然后用 DOM 方法来获得包含在XML文档里面的内容。你可以在here查看test.xml,在here查看修改后的脚本。

Step 5 – 使用数据返回

最后,让我们来发送一些数据到服务器,然后获得响应。我们的JavaScript这次将会请求一个动态页面,test.php将会获取我们发送的数据然后返回一个计算后的字符串 - "Hello, [user data]!",然后我们alert()出来。
首先我们加一个文本框到HTML,用户可以输入他们的姓名:
<label>Your name: 
<input type="text" id="ajaxTextbox" />
</label>
<span id="ajaxButton" style="cursor: pointer; text-decoration: underline">
Make a request
</span>
我们也给事件处理方法里面加一行获取文本框内容,并把它和服务器端脚本的url一起传递给 makeRequest() 方法:
  document.getElementById("ajaxButton").onclick = function() { 
var userName = document.getElementById("ajaxTextbox").value;
makeRequest('test.php',userName);
};
我们需要修改makeRequest()方法来接受用户数据并且传递到服务端。我们将把方法从 GET 改为 POST,把我们的数据包装成参数放到httpRequest.send():
function makeRequest(url, userName) {

...

httpRequest.onreadystatechange = alertContents;
httpRequest.open('POST', url);
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
httpRequest.send('userName=' + encodeURIComponent(userName));
}
如果服务端只返回一个字符串, alertContents() 方法可以和Step 3 一样。然而,服务端不仅返回计算后的字符串,还返回了原来的用户名。所以如果我们在输入框里面输入 “Jane”,服务端的返回将会像这样:
{"userData":"Jane","computedString":"Hi, Jane!"}
要在alertContents()使用数据,我们不能直接alert responseText, 我们必须转换数据然后 alert computedString属性:
function alertContents() {
if (httpRequest.readyState === XMLHttpRequest.DONE) {
if (httpRequest.status === 200) {
var response = JSON.parse(httpRequest.responseText);
alert(response.computedString);
} else {
alert('There was a problem with the request.');
}
}
}
test.php 文件如下:
$name = (isset($_POST['userName'])) ? $_POST['userName'] : 'no name';
$computedString = "Hi, " . $name;
$array = ['userName' => $name, 'computedString' => $computedString];
echo json_encode($array);
查看更多DOM方法, 请查看 Mozilla's DOM implementation 文档。
posted @ 2017-06-07 21:40  潮-汐  阅读(279)  评论(0编辑  收藏  举报