XMLHttpRequest
function createXHR(){
if (typeof XMLHttpRequest != "undefined"){
return new XMLHttpRequest();
} else if (typeof ActiveXObject != "undefined"){
if (typeof arguments.callee.activeXString != "string"){
var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0",
"MSXML2.XMLHttp"];
for (var i=0,len=versions.length; i < len; i++){
try {
var xhr = new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
} catch (ex){
//skip
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
} else {
throw new Error("No XHR object available.");
}
}
var xmlhttp=createXHR();
xmlhttp.onreadystatechange=function() //每当 readyState 属性改变时,就会调用该函数,用于异步请求,也可用onload,响应接收完毕会触发onload事件,无需检测readyState
{
//readyState表示请求过程的当前活动阶段 0: 请求未初始化,尚未open 1: 启动,open未send 2: 发送,已send,尚未接收到响应 3: 已接收部分响应数据 4: 请求已完成,且响应已就绪 status 200: "OK" 404: 未找到页面
if (xmlhttp.readyState==4)
{ try { //超时终止请求之后再访问status属性会报错
if((xmlhttp.status>=200&&xmlhttp.status<300)||(xmlhttp.status=304))//xmlhttp.status==304资源未更改,从缓存读
//responseText获得字符串形式的响应数据,responseXML获得XML形式的响应数据
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
else alert("Request was unsuccessful:"+xmlhttp.status);
}
}catch(ex){ }
}
xmlhttp.open("get",url,true); //相对于当前页面的url,不能跨域,异步请求,该方法只是启动一个请求以备发送
//xmlhttp.open("post",url,true);
//var data=new FormData(); 序列化表单
//data.append("name","Lancy");
//xmlhttp.send(data);
xmlhttp.setRequestHeader("MyHeader","MyValue");
xmlhttp.timeout=1000; //请求在1s内未返回自动终止,调用ontimeout事件处理程序
xmlhttp.ontimeout=function(){
alert("time out!")
}
xmlhttp.send(null); //发送请求
xmlhttp.abort() //接收到响应之前取消请求
收到响应后,数据会自动填充XHR对象的属性:
- responseText:作为响应主体被返回的文本
- status: 响应的HTTP状态
GET 还是 POST?
与 POST 相比,GET 更简单也更快,并且在大部分情况下都能用。GET请求可向url末尾添加参数,名值必须经过编码。在以下情况中,请使用 POST 请求:
- 无法使用缓存文件(更新服务器上的文件或数据库)
- 向服务器发送大量数据(POST 没有数据量限制)
- 发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠
为了避免得到缓存的结果,可以向 URL 添加一个唯一的 ID:
xmlhttp.open("GET","demo_get.asp?t=" + Math.random(),true);
如果需要像 HTML 表单那样 POST 数据,请使用 setRequestHeader()
来添加 HTTP 头。然后在 send() 方法中规定您希望发送的数据:
xmlhttp.open("POST","ajax_test.asp",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("fname=Bill&lname=Gates");
XMLHttpRequest.setRequestHeader() 是设置HTTP请求头部的方法。此方法必须在 open() 方法和 send() 之间调用。设置的语法
XMLHttpRequest.setRequestHeader(bstrHeader, bstrValue);
参数
bstrHeader 字符串,名称。
bstrValue 字符串,值。
setRequestHeader(“Content-type”, “application/x-www-form-urlencoded”);
setRequestHeader(“Content-length”, paramsSend.length);
setRequestHeader(“Connection”, “close”);
通常在HTTP协议里,客户端像服务器取得某个网页的时候,必须发送一个HTTP协议的头文件告诉服务器客户端要下载什么信息以及相关的参数,如:
GET /bb.asp?www=1234 HTTP/1.1
Accept: */*
Accept-Language: zh-cn
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)
Host: www.e4j.cn:89
Connection: Keep-Alive
Cookie: %C3%F7%CC%EC=%B0%CB;ASPSESSIONIDASDBSDRR=BLEDBIBBCGKBJAKJCFEJKGII
而 XMLHTTP 就是通过HTTP协议取得网站上的文件数据的,所以也要发送HTTP头给服务器。 但是 XMLHTTP 默认的情况下有些参数可能没有说明在HTTP头里,这是当我们需要修改或添加这些参数时就用到了setRequestHeader 方法。
就比如如果上面这段HTTP头文件内容是 XMLHTTP 提交默认的情况,当使用 setRequestHeader 方法后就这样,如:
XMLObject.setRequestHeader( “CONTENT-TYPE”, “application/x-www-form-urlencoded” )
setRequestHeader (“Connection”, “close”)
这时HTTP头信息就应该是这样了:
GET /bb.asp?www=1234 HTTP/1.1
Accept: */*
Accept-Language: zh-cn
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)
CONTENT-TYPE:application/x-www-form-urlencoded
Host: www.e4j.cn:89
Connection: close
Cookie: %C3%F7%CC%EC=%B0%CB;ASPSESSIONIDASDBSDRR=BLEDBIBBCGKBJAKJCFEJKGII
setRequestHeader方法只是XMLHTTP为添加或修改HTTP头提供的一个接口方法而已, 至于里面的值则是HTTP协议的含义,当然也可以放自己的东西进去,即使IIS不能识别你的信息也不会报错
如: setRequestHeader (“MyName”, “Supermanking”)
虽然IIS不会报错,但这个信息也可以有用,可以在ASP程序里读取HTTP头信息分析是否有 MyName: Supermanking 信息,可根据你的需求来做处理,还有,CONTENT-TYPE:application/x-www-form-urlencoded含义是表示客户端提交给服务器文本内容的编码方式是URL编码,即除了标准字符外,每字节以双字节16进制前加个“%”表示
当然还有其他编码方式,如:CONTENT-TYPE:multipart/form-data
至于:Content-length 就是表示提交的数据字节大小
http有几种提交方式,其中比较常用的就是 GET 和 POST
这个标志就放在HTTP头开头的地方,这样讲容易理解点
GET 方式是没有提交内容的,所以 Content-length 在 GET 模式下是无效的.
GET 传参数的方式就是通过虚拟地址传送,如:
GET /bb.asp?www=1234 HTTP/1.1
参数全部就只有 “www=1234” 这么多
如果用POST的话就有些不同,POST是将参数放到HTTP后面的,就以上面的HTTP作范例,用POST的方法传参数
POST /bb.asp HTTP/1.1
Accept: */*
Accept-Language: zh-cn
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)
CONTENT-TYPE:application/x-www-form-urlencoded
Host: www.e4j.cn:89
Content-length: 8
Connection: close
Cookie: %C3%F7%CC%EC=%B0%CB;ASPSESSIONIDASDBSDRR=BLEDBIBBCGKBJAKJCFEJKGII
www=1234
这时,数据就需要说明字节大小了
至于 Connection: Close,很明显英文的意思是 连接:关闭
只是客户端在提交数据时告诉服务器让谁先关闭连接而已。
在XMLHttpRequest发送请求之前加上以下头部可以避免缓存:
XMLHttpRequest.setRequestHeader("If-Modified-Since","0");
XMLHttpRequest.send(null);
If-Modified-Since的头标签的作用
我们都知道浏览器是有缓存的,其实缓存里存储的不只是网页文件,还有服务器发过来的该文件的最后服务器修改时间。
If-Modified-Since是标准的HTTP请求头标签,在发送HTTP请求时,把浏览器端缓存页面的最后修改时间一起发到服务器去,服务器会把这个时间与服务器上实际文件的最后修改时间进行比较。
如果时间一致,那么返回HTTP状态码304(不返回文件内容),客户端接到之后,就直接把本地缓存文件显示到浏览器中。
如果时间不一致,就返回HTTP状态码200和新的文件内容,客户端接到之后,会丢弃旧文件,把新文件缓存起来,并显示到浏览器中。
解决缓存问题三个方法
1.时间戳方法 ——即在每次请求的url后面加上当前时间的字符串或其他类似的不会重复的随机字符串,这样浏览器每次发出的是不同的url,即会当做不同的请求来处理,而不会从缓存中读取。
if(url.indexOf("?")>=0){//判断url中是否已经带有参数
url = url + "&t=" + (new Date()).valueOf();
}else{
url = url + "?t=" + (new Date()).valueOf();
}
2、在HTTP header上处理缓存
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="Cache-Control" content="no-cache,no-store, must-revalidate" />
<meta http-equiv="expires" content="Thu, 01 Jan 1970 00:00:01 GMT" />
<meta http-equiv="expires" content="0" />
- 在XMLHttpRequest发送请求之前加上:
XMLHttpRequest.setRequestHeader("If-Modified-Since","0");
XMLHttpRequest.send(null);
Fetch
fetch 规范与 jQuery.ajax() 主要有两种方式的不同:
- 从 fetch()返回的 Promise 将不会拒绝HTTP错误状态, 即使响应是一个 HTTP 404 或 500。相反,它会正常解决 (其中ok状态设置为false), 并且仅在网络故障时或任何阻止请求完成时,它才会拒绝。
- 默认情况下, fetch在服务端不会发送或接收任何 cookies, 如果站点依赖于维护一个用户会话,则导致未经认证的请求(要发送 cookies,必须发送凭据头).
fetch(input[, init]);
input定义要获取的资源。这可能是:
- 一个 USVString 字符串,包含要获取资源的 URL。
- 一个 Request 对象。Request
var myRequest = new Request('flowers.jpg');
var myURL = myRequest.url; // http://localhost:8000/flowers.jpg
var myMethod = myRequest.method; // GET
init 可选,一个配置项对象,包括所有对请求的设置。可选的参数有:
- method: 请求使用的方法,如 GET、POST。
- headers: 请求的头信息,形式为 Headers 的对象或包含 ByteString 值的对象字面量。
- body: 请求的 body 信息:可能是一个 Blob、BufferSource、FormData、URLSearchParams 或者 USVString 对象。注意 GET 或 HEAD 方法的请求不能包含 body 信息。
- mode: 请求的模式,如 cors、 no-cors 或者 same-origin。
- credentials: 请求的 credentials,如 omit、same-origin 或者 include。为了在当前域名内自动发送 cookie , 必须提供这个选项, 从 Chrome 50 开始, 这个属性也可以接受 FederatedCredential 实例或是一个 PasswordCredential 实例。
- cache: 请求的 cache 模式: default 、 no-store 、 reload 、 no-cache 、 force-cache 或者 only-if-cached 。
- redirect: 可用的 redirect 模式: follow (自动重定向), error (如果产生重定向将自动终止并且抛出一个错误), 或者 manual (手动处理重定向). 在Chrome中,Chrome 47之前的默认值是 follow,从 Chrome 47开始是 manual。
- referrer: 一个 USVString 可以是 no-referrer、client或一个 URL。默认是 client。
- referrerPolicy: Specifies the value of the referer HTTP header. May be one of no-referrer、 no-referrer-when-downgrade、 origin、 origin-when-cross-origin、 unsafe-url 。
- integrity: 包括请求的 subresource integrity 值 ( 例如: sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=)。
let myImage = document.querySelector('img');
var myHeaders = new Headers();
var myInit = { method: 'GET',
headers: myHeaders,
mode: 'cors',
cache: 'default' };
fetch('flowers.jpg',myInit)
.then(function(response) {
return response.blob();
})
.then(function(myBlob) {
let objectURL = URL.createObjectURL(myBlob);
myImage.src = objectURL;
});
var myHeaders = new Headers();
var myInit = { method: 'GET',
headers: myHeaders,
mode: 'cors',
cache: 'default' };
var myRequest = new Request('flowers.jpg', myInit);
fetch(myRequest).then(function(response) {
return response.blob();
}).then(function(myBlob) {
var objectURL = URL.createObjectURL(myBlob);
myImage.src = objectURL;
});
Request() 和 fetch() 接受同样的参数。你甚至可以传入一个已存在的 request 对象来创造一个拷贝:
var anotherRequest = new Request(myRequest,myInit);
这里我们通过网络获取一个图像并将其插入到一个 元素中。最简单的用法是只提供一个参数用来指明想fetch到的资源路径,然后返回一个包含响应结果的promise(一个 Response 对象)。当然它只是一个 HTTP 响应,而不是真的图片。为了获取图片的内容,我们需要使用 blob() 方法(在Body mixin 中定义,被 Request 和 Response 对象实现, Fetch API 中的 Body mixin 代表 response/requestd的body属性,允许你声明其内容类型是什么以及应该如何处理,一个 Blob对象表示一个不可变的, 原始数据的类似文件对象。)。
Body 类定义了以下方法 (这些方法都被 Request 和Response所实现)以获取body内容. 这些方法都会返回一个被解析后的promise对象和数据.
- arrayBuffer()
- blob()
- json()
- text()
- formData()
比起XHR来,这些方法让非文本化的数据使用起来更加简单。
功能检测
Fetch API 的支持情况,可以通过检测 Headers、Request、Response 或 fetch() 是否在 Window 或 Worker 域中。比如你可以这样做:
if(self.fetch) {
// run my fetch request here
} else {
// do something with XMLHttpRequest?
}
检测请求是否成功
如果遇到网络故障,fetch() promise 将会 reject,带上一个 TypeError 对象。虽然这个情况经常是遇到了权限问题或类似问题——比如 404 不是一个网络故障。想要精确的判断 fetch() 是否成功,需要包含 promise resolved 的情况,此时再判断 Response.ok 是不是为 true。类似以下代码:
fetch('flowers.jpg').then(function(response) {
if(response.ok) {
response.blob().then(function(myBlob) {
var objectURL = URL.createObjectURL(myBlob);
myImage.src = objectURL;
});
} else {
console.log('Network response was not ok.');
}
})
.catch(function(error) {
console.log('There has been a problem with your fetch operation: ' + error.message);
});
用 async/await 优化
try {
let response = await fetch(url);
let data = response.json();
console.log(data);
} catch(e) {
console.log("Oops, error", e);
}
// 注:这段代码如果想运行,外面需要包一个 async function
参考链接
https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch