-
HTTP请求
现在,很多浏览器都可以直接从javaScript中初始化HTTP请示并获取结果,完全不用隐藏框架和其他取巧的小技巧了。这样功能的的核心是微软创建的XML HTTP请求对象。这个对象是与MSXML一起出现的。XML HTTP请求的本质是添加了额外的用于发送和接收XML代码的功能的普通HTTP请求。
与IE中的XML DOM一样,XML HTTP请求对象有多种版本,所以需要一个用于确保使用的是最新版本的函数:
function createXMLHTTP() { var arrSignatures = ["MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"]; for (var i = 0; i < arrSignatures.length; i++) { try { var oRequest = new ActiveXObject(arrSignatures[i]); alert(i); return oRequest; } catch (oError) { //ignore } } throw new Error("MSXML is not installed on your system."); }
创建好XML HTTP请求后,可用open()方法来指定要发送的请求。这个方法有三个参数:要发送的请求类型(GET、POST或者其他受服务器支持的HTTP方法)、请求的URL以及表示请求是否应该以异步方式发送的布尔值(与XML DOM的load()方法一样),例如:
oRequest.open('get','example.txt',false);//false为同步发送
打开这个请求后,还要用send()方法将其发送出去。这个方法一定要有一个参数,不过大多数情况下都可以用null
oRequest.send(null);
响应的过程中,oRequest.readyState 会存入当前服务器相应状态,返回响应后,oRequest.status 属性中会放入请求的HTTP状态(200是正常,404没有找到页面等待)。同时在oRequest.statusText 属性中放入描述状态信息,在oRequest.responseText 属性放入从服务器接收到的文本。另外,如果返回的是XML,还要在oRequest.responseXML 属性中放入XML DOM对象,如:
var oRequest = createXMLHTTP(); oRequest.open("get", "example.xml", false); oRequest.send(null); alert("Status is " + oRequest.status + " (" + oRequest.statusText + ")"); alert("Response text is: " + oRequest.responseText); alert("Tag name of document element is: " + oRequest.responseXML.documentElement.tagName);
上面都是同步发送请求的示例,如果要发异步请求,须使用onreadystatechange 事件处理函数,并检查readyState属性是否等于4(与异步解析XML DOM一样)。对于异步调用,可以通过调用abort()方法在readyState变成4之前取消请求操作:
var oRequest = createXMLHTTP(); oRequest.open("get", "example.txt", true); oRequest.onreadystatechange = function () { if (oRequest.readyState == 3) { oRequest.abort(); } else { if (oRequest.readyState == 4) { alert("Status is " + oRequest.status + " (" + oRequest.statusText + ")"); alert("Response text is: " + oRequest.responseText); } } }; oRequest.send(null);
在此例中,不会出现警告框,因为请求在readyState为3时被中止了。
使用HTTP头部
XML HTTP请求对象提供了获取和设置头部的方法,第一个方法是getAllResponseHeaders ()方法,返回所有响应的HTTP头部信息字符串,返回样例:
Date: Sun, 14 Nov 2004 18:04:03 GMT
Server: Apache/1.3.29 (Unix)
Vary: Accept
x-Powered-By: PHP/4.3.8
Connection: Close
Content-Type: text/html; charset=iso-8859-1
如要获取 Server 首部的值,可以这样:
oRequest.getResponseHeader(‘Server’);
除了读取请求首部信息,还可以设计自己的首部信息,如:
oRequest.setRequestHeader('myheader','yippee'); oRequest.setRequestHeader('weather','warm');
这里假设你已经设计了一些服务器端逻辑来根据这些首部信息提供额外的功能或者对请求的计算。
其他浏览器中的XML HTTP实现
Mozilla中有一个名为XMLHttpRequest 的JavaScript,行为完全与微软的版本相同。Safari(1.2)与Opera(7.6)也实现了。
若要创建一种统一的XML HTTP请求对象的创建方法,只需在页面中添加下面代码:
if (typeof XMLHttpRequest == "undefined" && window.ActiveXObject) { function XMLHttpRequest() {//让IE也支持XMLHttpRequest var arrSignatures = ["MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"]; for (var i = 0; i < arrSignatures.length; i++) { try { var oRequest = new ActiveXObject(arrSignatures[i]); return oRequest; } catch (oError) { //ignore } } throw new Error("MSXML is not installed on your system."); } }
可以使用下面一行代码在所有支持XML HTTP请求对象的浏览器中创建这个对象:
var oRequest = new XMLHttpRequest();
进行GET请求
每次在浏览器中输入URL并打开页面时,就是在向服务器发送一个GET请求。GET请求的参数是用问题追加到URL的结尾,后面跟着用&号连接起来的名称/值。每个名称和值都必须在编码后才能用在URL中(在JavaScript中可以用encodeURIComponent()进行编码)。URL最大长度为2KB 。
要是用XMLHTTP请求对象发送一个GET请求,只需将URL(包含所有的参数)传入open()方法,同时第一个参数设为get。因为参数须追加到URL的末尾,所有最好用这个函数来处理这个细节:
function addURLParam(sURL, sParamName, sParamValue) { sURL += (sURL.indexOf("?") == -1 ? "?" : "&"); sURL += encodeURIComponent(sParamName) + "=" + encodeURIComponent(sParamValue); return sURL; }
如下使用:
var sURL = "http://localhost/reflectpost.php"; sURL = addPostParam(sURL, "name", "Nicholas"); sURL = addPostParam(sURL, "book", "Professional JavaScript"); oRequest.open('get',sURL,false); oRequest.send(null);
进行POST请求
一般来说,POST请求用于在表单中输入数据后的提交过程,因为POST可以比GET方式发送更多的数据(大约为2GB)。使用一个函数来处理POST请求的参数:
function addPostParam(sParams, sParamName, sParamValue) { if (sParams.length > 0) { sParams += "&"; } //POST 方式时应该可以不用encodeURIComponent编码??? return sParams + encodeURIComponent(sParamName) + "=" + encodeURIComponent(sParamValue); }
如下使用:
var sParams = ""; sParams = addPostParam(sParams, "name", "Nicholas"); sParams = addPostParam(sParams, "book", "Professional JavaScript"); //post方式时要设置此头部信息 oRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); oRequest.open('post','page.php',false); oRequest.send(sParams);
-
LiveConnect请求
Netscap Navigator引用了LiveConnect概念,一种可以让JavaScript与Java类实现交互的能力。用户必须安装Java运行时环境(JRE)才能使用这个功能,同时在浏览器必须启用java。几乎所有现在的浏览器(除IE之外)都支持LiveConnect,它允许访问java提供的所有HTTP相关的库。
进行GET请求
function httpGet(sURL) { var sResponseText = ""; //创建java.net.URL实例,注:使用LiveConnect时,须提供完整类名 var oURL = new java.net.URL(sURL); //打开一个输入流(InputStream)并使用读取器来获取数据 var oStream = oURL.openStream(); var oReader = new java.io.BufferedReader(new java.io.InputStreamReader(oStream)); var sLine = oReader.readLine(); while (sLine != null) { sResponseText += sLine + "\n"; sLine = oReader.readLine(); } oReader.close(); return sResponseText; } function getServerInfo() { var sResponseText = httpGet("http://localhost/example.txt"); alert("Response text is: " + sResponseText); }
不好的是,使用LiveConnect时,不能获取完全相同的信息,如状态。同时,这个函数只能进行同步使用,不能创建异步调用。还有就是LiveConnect要求输入完整的请求URL,从http://开始。因为,这个在Java对象没有任何解释相对的URL上下文。
进行POST请求
与GET方式不同的是,POST方式代码要使用Connection对象来协助进行请求:
function httpPost(sURL, sParams) { var oURL = new java.net.URL(sURL); //返回URLConnection var oConnection = oURL.openConnection(); /*因为POST请求可看作是双向的,所以必须使用setDoInput与 setDoOutput()方法 将连接设成接受输入和输出。*/ oConnection.setDoInput(true); oConnection.setDoOutput(true); //不使用缓存 oConnection.setUseCaches(false); //POST方式传递时需设置成application/x-www-form-urlencoded oConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); //---写数据 var oOutput = new java.io.DataOutputStream(oConnection.getOutputStream()); oOutput.writeBytes(sParams); oOutput.flush(); oOutput.close(); //---读数据 var sLine = "", sResponseText = ""; var oInput = new java.io.DataInputStream(oConnection.getInputStream()); sLine = oInput.readLine(); while (sLine != null) { sResponseText += sLine + "\n"; sLine = oInput.readLine(); } oInput.close(); return sResponseText; } function addPostParam(sParams, sParamName, sParamValue) { if (sParams.length > 0) { sParams += "&"; } return sParams + encodeURIComponent(sParamName) + "=" + encodeURIComponent(sParamValue); } function getServerInfo() { var sParams = ""; sParams = addPostParam(sParams, "name", "Nicholas"); sParams = addPostParam(sParams, "book", "Professional JavaScript"); var sResponseText = httpPost("http://localhost/reflectpost.php", sParams); alert("Response text is: " + sResponseText); }
-
通用HTTP请求
以下脚本可以不用区分浏览器,也不用担心是支持XML HTTP请求还是支持LiveConnect,只要一种支持即可使用。此脚本是在书源上修改的,增加了服务器以responseXML方式的返回,最后还是附上书上的源码。通用脚本如下:
//POST方式时参数连接 function addPostParam(sParams, sParamName, sParamValue) { if (sParams.length > 0) { sParams += "&"; } return sParams + encodeURIComponent(sParamName) + "=" + encodeURIComponent(sParamValue); } //URL方式(GET)时参数连接 function addURLParam(sURL, sParamName, sParamValue) { sURL += (sURL.indexOf("?") == -1 ? "?" : "&"); sURL += encodeURIComponent(sParamName) + "=" + encodeURIComponent(sParamValue); return sURL; } //LiveConnect的Post方式 function httpPost(sURL, sParams, returnXML) { var oURL = new java.net.URL(sURL); var oConnection = oURL.openConnection(); oConnection.setDoInput(true); oConnection.setDoOutput(true); oConnection.setUseCaches(false); oConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); //--写数据 var oOutput = new java.io.DataOutputStream(oConnection.getOutputStream()); oOutput.writeBytes(sParams);//写入参数 oOutput.flush(); oOutput.close(); //--读数据 var sLine = "", sResponseText = ""; var oInput = new java.io.DataInputStream(oConnection.getInputStream()); sLine = oInput.readLine(); while (sLine != null) { sResponseText += sLine + "\n"; sLine = oInput.readLine(); } oInput.close(); if (returnXML) {//如果要求以XMLDOM形势返回 //XmlDom对象请参见《JavaScript中的XML》一节 var oXmlDom = new XmlDom(); //注,这里要同步解析,以防还未解析完成就返回给用户了, //如果为Mozilla则无效,因为DOMParser应该只支持同步载入XML oXmlDom.async = false; return oXmlDom.loadXML(sResponseText); } else { return sResponseText; } } //LiveConnect的Get方式 function httpGet(sURL, returnXML) { var sResponseText = ""; var oURL = new java.net.URL(sURL); var oStream = oURL.openStream(); var oReader = new java.io.BufferedReader(new java.io.InputStreamReader(oStream)); var sLine = oReader.readLine(); while (sLine != null) { sResponseText += sLine + "\n"; sLine = oReader.readLine(); } oReader.close(); //返回从服务器读取的数据 if (returnXML) {//如果要求以XMLDOM形势返回 //XmlDom对象请参见《JavaScript中的XML》一节 var oXmlDom = new XmlDom(); //注,这里要同步解析,以防还未解析完成就返回给用户了, //如果为Mozilla则无效,因为DOMParser应该只支持同步载入XML oXmlDom.async = false; return oXmlDom.loadXML(sResponseText); } else { return sResponseText; } } //如果是IE,且支持MSXML时 if (typeof XMLHttpRequest == "undefined" && window.ActiveXObject) { //IE模拟Mozilla中XMLHttpRequest对象 function XMLHttpRequest() { var arrSignatures = ["MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"]; for (var i = 0; i < arrSignatures.length; i++) { try { var oRequest = new ActiveXObject(arrSignatures[i]); return oRequest; } catch (oError) { //ignore } } throw new Error("MSXML is not installed on your system."); } } //是否支持XMLHTTP请求 var bXmlHttpSupport = (typeof XMLHttpRequest == "object" || window.ActiveXObject); //Http对象存放自定义方法 var Http = new Object; /* * 以get方式向服务器发送请求,如果浏览器不支持XMLHTTP时,使用 * LiveConnect方式发送与接收 * sURL:发送请求URL * fnCallback: 回调函数 * returnXML: 是否以XML形式返回 */ Http.get = function (sURL, fnCallback, returnXML) { if (bXmlHttpSupport) {//支持XMLHTTP var oRequest = new XMLHttpRequest(); oRequest.open("get", sURL, true);//get方式下的异步发送 oRequest.onreadystatechange = function () { if (oRequest.readyState == 4) { if (oRequest.status == 200) { //把响应的数据传递给回调函数 if (returnXML) { fnCallback(oRequest.responseXML); } else { fnCallback(oRequest.responseText); } } else { alert("Status = " + oRequest.status + "(" + oRequest.responseText + ")"); } } }; oRequest.send(null); } else { //如果不支持XMLHTTP时,且支持LiveConnect时使用LiveConnect if (navigator.javaEnabled() && typeof java != "undefined" && typeof java.net != "undefined") { //模仿异步调用 setTimeout(function () { fnCallback(httpGet(sURL, returnXML)); }, 10); } else { alert("Your browser doesn't support HTTP requests."); } } }; /* * 以post方式向服务器发送请求,如果浏览器不支持XMLHTTP时,使用 * LiveConnect方式发送与接收 * sURL: 发送请求URL * sParams: 要发送的参数 * fnCallback: 回调函数 * returnXML: 是否以XML形式返回 */ Http.post = function (sURL, sParams, fnCallback, returnXML) { if (bXmlHttpSupport) { //支持XMLHTTP var oRequest = new XMLHttpRequest(); oRequest.open("post", sURL, true);//post方式下的异步发送 //post方式时要设置此头部信息 oRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); oRequest.onreadystatechange = function () { if (oRequest.readyState == 4) { if (oRequest.status == 200) { if (returnXML) {//如果要求以XMLDOM形势返回 fnCallback(oRequest.responseXML); } else { fnCallback(oRequest.responseText); } } else { alert("Status = " + oRequest.status + "(" + oRequest.responseText + ")"); } } }; oRequest.send(sParams); } else { if (navigator.javaEnabled() && typeof java != "undefined" && typeof java.net != "undefined") { //模仿异步调用 setTimeout(function () { fnCallback(httpPost(sURL, sParams, returnXML)); }, 10); } else { alert("Your browser doesn't support HTTP requests."); } } };
如下使用:
var sURL = "http://localhost/example.txt"; Http.get(sURL, function (sData) {//发送get请求 alert("Data from server: " + sData); }); var sParams = ""; sParams = addPostParam(sParams, "name", "Nicholas"); sParams = addPostParam(sParams, "book", "Professional JavaScript"); Http.post(sURL, sParams, function (sData) {//发送post请求 alert("Data from server: " + sData); });